[英]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([©_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_ptr
和assembler
(它们是简单的指针,您可以毫无问题地复制它们):
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.