首页 > 解决方案 > Simulink“访问冲突”写入 C++ lambda 函数捕获列表中的 PWork 变量

问题描述

我有一个 C++ S-Function,它通过 std::thread、std::async 和回调处理一组线程操作。问题是其中一个回调是一个 S-Function,它在捕获列表中有一个缓冲区。此缓冲区位于 Simulink 模型的 PWork 中。但是,似乎一旦我尝试写入 Matlab,它就会崩溃。

下面是我的 S-Function(仅 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);
    });
}

从数据服务器工作线程(不同于 Simulink 主线程)调用处理程序。回调函数内的其他操作可以顺利进行(读取参数,执行其他操作......)。

任何提示为什么会发生这种情况?在将其集成到 Simulink 之前,相同的代码在一个独立的可执行文件中运行。

标签: c++matlabc++11simulink

解决方案


您正在copy_buffer_ptr通过引用捕获(堆栈局部变量)。该引用将在mdlStart返回后立即悬空,之后调用 lambda 是未定义的行为。(这也适用于assembler)。

解决方法是简单地捕获copy_buffer_ptr并按assembler值(它们是简单的指针,您可以毫无问题地复制它们):

server->attachDataHandler([copy_buffer_ptr, assembler](const ThreadedDataServer::buffer_t & buffer, size_t num_bytes)
{
  /* etc. */
});

如果你有一个 lambda 会比当前范围更长寿,那么在通过引用捕获任何东西之前要仔细考虑——如果它是堆栈本地的,你可能会被烧毁。


推荐阅读