Simulink“;访问违规”;写入C+的捕获列表中的PWork变量+;lambda函数 我有一个C++函数,它通过STD::Type:STD::AsiNC和回调来处理一组线程操作。 问题是其中一个回调是一个S函数,它在捕获列表中有一个缓冲区。该缓冲区在Simulink模型的工作中。然而,似乎Matlab在我试图编写时就崩溃了
下面是我的S函数(仅mdlStart函数)的最小崩溃示例,其中包含相关代码: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
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);
});
}
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);
}
});