繁体   English   中英

Simulink“访问冲突”写入 C++ lambda 函数捕获列表中的 PWork 变量

[英]Simulink "Access Violation" writing to PWork variable in capture list of C++ lambda function

我有一个 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 之前,相同的代码在独立的可执行文件中工作。

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

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

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

如果您的 lambda 超过当前范围,请在通过引用捕获任何内容之前深思熟虑 - 如果它是堆栈本地的,您可能会被烧毁。

感谢@max-langhof 的回答(悬空指针)和一些额外的工作,我终于找到了一个解决方案:

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);
        }
    });

这个实现解决了两个问题:

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

它现在正在工作:-)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM