Simulink“;访问违规”;写入C+的捕获列表中的PWork变量+;lambda函数 我有一个C++函数,它通过STD::Type:STD::AsiNC和回调来处理一组线程操作。 问题是其中一个回调是一个S函数,它在捕获列表中有一个缓冲区。该缓冲区在Simulink模型的工作中。然而,似乎Matlab在我试图编写时就崩溃了

Simulink“;访问违规”;写入C+的捕获列表中的PWork变量+;lambda函数 我有一个C++函数,它通过STD::Type:STD::AsiNC和回调来处理一组线程操作。 问题是其中一个回调是一个S函数,它在捕获列表中有一个缓冲区。该缓冲区在Simulink模型的工作中。然而,似乎Matlab在我试图编写时就崩溃了,c++,matlab,c++11,simulink,C++,Matlab,C++11,Simulink,下面是我的S函数(仅mdlStart函数)的最小崩溃示例,其中包含相关代码: static void mdlStart(SimStruct *S) { ssGetPWork(S)[0] = (void *) new ThreadedDataServer(); ssGetPWork(S)[1] = (void *) new DatagramAssembler(); ssGetPWork(S)[2] = (void *) new MyBufferType(); // actu

下面是我的S函数(仅mdlStart函数)的最小崩溃示例,其中包含相关代码:

static void mdlStart(SimStruct *S)
{
    ssGetPWork(S)[0] = (void *) new ThreadedDataServer();
    ssGetPWork(S)[1] = (void *) new DatagramAssembler();
    ssGetPWork(S)[2] = (void *) new MyBufferType(); // actually an std::array<char, LARGENUMBER>

    auto server          = (ThreadedDataServer *) ssGetPWork(S)[0];
    auto assembler       = (DatagramAssembler*)   ssGetPWork(S)[1];
    auto copy_buffer_ptr = (MyBufferType *)       ssGetPWork(S)[2];

    server->attachDataHandler([&copy_buffer_ptr, &assembler](const ThreadedDataServer::buffer_t & buffer, size_t num_bytes)
    {
        /* Minimal crashing action */
        copy_buffer_ptr->at(5) = 'b'; // Any index != 0
        /* Original code */
        //std::copy(buffer.begin(), buffer.begin() + num_bytes, copy_buffer_ptr->data());
        //assembler->feedData(*copy_buffer_ptr, num_bytes);
    });
}
static void mdlStart(SimStruct*S)
{
ssGetPWork[0]=(void*)新线程数据服务器();
ssGetPWork[1]=(void*)新DatagramMasseBler();
ssGetPWork[2]=(void*)new MyBufferType();//实际上是一个std::数组
自动服务器=(ThreadedDataServer*)ssGetPWork[0];
自动汇编程序=(DatagramAssembler*)ssGetPWork[1];
自动复制缓冲区ptr=(MyBufferType*)ssGetPWork[2];
server->attachDataHandler([©\u buffer\u ptr,&assembler](const-ThreadedDataServer::buffer\u t&buffer,size\u num\u bytes)
{
/*最小碰撞动作*/
复制_buffer_ptr->at(5)='b';//任何索引!=0
/*原始代码*/
//std::copy(buffer.begin(),buffer.begin()+num_字节,copy_buffer_ptr->data());
//汇编程序->feedData(*复制缓冲区,字节数);
});
}
处理程序从数据服务器工作线程调用(与Simulink主线程不同)。回调函数中的其他操作工作顺利(读取参数、执行其他操作…)


有什么线索说明为什么会发生这种情况吗?在将其集成到Simulink中之前,相同的代码在一个独立的可执行文件中工作。

您正在通过引用捕获
copy\u buffer\u ptr
(堆栈局部变量)。只要
mdlStart
返回,该引用就会悬空,之后调用lambda是未定义的行为。(这也适用于
汇编程序

解决方法是简单地按值捕获
copy\u buffer_ptr
assembler
(它们是简单的指针,您可以直接复制它们而不出问题):


如果您的lambda将超过当前范围,请在通过引用捕获任何内容之前仔细考虑—如果它是堆栈本地的,您可能会被烧死。

多亏了@max langhof answer(悬空指针)和一些额外的工作,我终于找到了一个解决方案:

static void mdlStart(SimStruct *S)
{
    ssGetPWork(S)[0] = (void *) new ThreadedDataServer();
    ssGetPWork(S)[1] = (void *) new DatagramAssembler();
    ssGetPWork(S)[2] = (void *) new MyBufferType(); // actually an std::array<char, LARGENUMBER>
    ssGetPWork(S)[3] = (void *) new std::mutex();

    auto server          = (ThreadedDataServer *) ssGetPWork(S)[0];
    auto assembler       = (DatagramAssembler*)   ssGetPWork(S)[1];
    auto copy_buffer_ptr = (MyBufferType *)       ssGetPWork(S)[2];
    auto assembly_mutex  = (std::mutex *)         ssGetPWork(S)[3];

    server->attachDataHandler([copy_buffer_ptr, assembler, assembly_mtx](const ThreadedDataServer::buffer_t & buffer, size_t num_bytes)
    {
        // Mutex scoped lock
        {
            std::lock_guard<std::mutex> lckg(assembly_mutex);
            std::copy(buffer.begin(), buffer.begin() + num_bytes, copy_buffer_ptr.data());
            assembler.feedData(copy_buffer_ptr, num_bytes);
        }
    });
static void mdlStart(SimStruct*S)
{
ssGetPWork[0]=(void*)新线程数据服务器();
ssGetPWork[1]=(void*)新DatagramMasseBler();
ssGetPWork[2]=(void*)new MyBufferType();//实际上是一个std::数组
ssGetPWork[3]=(void*)新std::mutex();
自动服务器=(ThreadedDataServer*)ssGetPWork[0];
自动汇编程序=(DatagramAssembler*)ssGetPWork[1];
自动复制缓冲区ptr=(MyBufferType*)ssGetPWork[2];
自动组装_mutex=(std::mutex*)ssGetPWork[3];
服务器->attachDataHandler([copy_buffer_ptr,assembler,assembly_mtx](const ThreadedDataServer::buffer_t&buffer,size_t num_bytes)
{
//互斥作用域锁
{
标准:锁定保护lckg(组件互斥);
std::copy(buffer.begin(),buffer.begin()+num_字节,copy_buffer_ptr.data());
feedData(复制缓冲区ptr,num字节);
}
});
此实现解决了两个问题:

  • 捕获列表中的变量引用堆栈中的指针,该指针以悬空指针结束,并导致崩溃
  • 对数据处理程序的几个调用同时访问缓冲区和汇编程序对象,显然导致了不同的访问冲突

它现在可以工作了:-)

谢谢!它可以工作了,但只有结合额外的防止并发访问的保护。我会把它写在我的问题中。我现在觉得有点傻……可能需要休息一下。
static void mdlStart(SimStruct *S)
{
    ssGetPWork(S)[0] = (void *) new ThreadedDataServer();
    ssGetPWork(S)[1] = (void *) new DatagramAssembler();
    ssGetPWork(S)[2] = (void *) new MyBufferType(); // actually an std::array<char, LARGENUMBER>
    ssGetPWork(S)[3] = (void *) new std::mutex();

    auto server          = (ThreadedDataServer *) ssGetPWork(S)[0];
    auto assembler       = (DatagramAssembler*)   ssGetPWork(S)[1];
    auto copy_buffer_ptr = (MyBufferType *)       ssGetPWork(S)[2];
    auto assembly_mutex  = (std::mutex *)         ssGetPWork(S)[3];

    server->attachDataHandler([copy_buffer_ptr, assembler, assembly_mtx](const ThreadedDataServer::buffer_t & buffer, size_t num_bytes)
    {
        // Mutex scoped lock
        {
            std::lock_guard<std::mutex> lckg(assembly_mutex);
            std::copy(buffer.begin(), buffer.begin() + num_bytes, copy_buffer_ptr.data());
            assembler.feedData(copy_buffer_ptr, num_bytes);
        }
    });