C++ QSharedPointer或std::shared\u ptr的生命周期
在我的申请中 我有一个C++ QSharedPointer或std::shared\u ptr的生命周期,c++,multithreading,qt,shared-ptr,qsharedpointer,C++,Multithreading,Qt,Shared Ptr,Qsharedpointer,在我的申请中 我有一个MainWindow(它是QtMainWindow类)和一个Acquisiton类(它是QThread类) 这是我非常简化的获取类 //entry point of the thread void Acquisition::run () { uint8_t* image_addr; QSharedPointer<uint8_t> image(new uint8_t[IMG_SIZE]); for
MainWindow
(它是QtMainWindow
类)和一个Acquisiton
类(它是QThread
类)
这是我非常简化的获取类
//entry point of the thread
void Acquisition::run ()
{
uint8_t* image_addr;
QSharedPointer<uint8_t> image(new uint8_t[IMG_SIZE]);
for (;;)
{
if (isInterruptionRequested())
return;
// here, usb_read() give me the adress of a elem in the ring buffer
img_addr = usb_read(...);
// the ring buffer can possibly be rewritten on the next usb_read() (if bufferlength = 1) so I copy the data into my QSharedPointer
std::memcpy(image.data(), image_addr, sizeof(IMG_SIZE));
// I send this image
emit imageSent(image);
}
}
//线程的入口点
无效获取::运行()
{
uint8_t*图像地址;
Q共享指针图像(新单元8_t[IMG_大小]);
对于(;;)
{
如果(isInterruptionRequested())
返回;
//这里,usb_read()给我环形缓冲区中一个元素的地址
img_addr=usb_读取(…);
//环形缓冲区可能会在下一次usb_read()时重写(如果bufferlength=1),因此我将数据复制到我的QSharedPointer中
std::memcpy(image.data(),image_addr,sizeof(IMG_SIZE));
//我发送这张图片
发射图像发送(图像);
}
}
在我的主窗口里,我
// the slot for the signal imageSent
void newImage(QSharedPointer<uint8_t> image)
{
// process and draw image
}
//发送的信号的插槽
void newImage(QSharedPointer映像)
{
//处理并绘制图像
}
我不理解QSharedPointer(和std::shared_ptr)的生命周期(想象一下std::shared_ptr的相同代码)
我的QSharedPointer是否始终有效?
如果在处理过程中(MainWindow),usb_read()发生,memcpy在我的图像上写入,会附加什么
在一个相关问题中:
我发现,如果采集线程在数据处理过程中停止,QSharedPointer会使我的数据保持有效
在这种情况下,是我的信号被取消,我的值被复制到某个地方,还是线程等待我的主窗口完成处理
谢谢
我的QSharedPointer是否始终有效
只有在您将数据复制到它之后,如果是,则只要它的任何实例存在,只要您的Acquisition
类型的对象存在,它就会有效
如果在处理过程中(MainWindow),usb_read()发生了什么
记忆会写在我的图像上
竞争条件。在主窗口中处理时,您必须使用互斥锁锁定资源。智能指针本身不是线程安全的,但是QSharedPointer
使用原子整数进行引用计数,因此共享是线程安全的。同样,内容不是
在这种情况下,我的信号是否被取消,我的值是否被复制到某个地方或
线程是否正在等待我的主窗口完成处理
这取决于连接对象的方式。默认情况下,当两个qObject
位于两个不同的线程中时,连接将自动Qt::QueuedConnection
,在这种情况下,参数将首先复制(即使作为常量引用发送)在内部作为事件发布到接收方线程中。这要求参数可复制,接收方线程运行事件循环。但是,如果出于某种原因执行同一线程中默认连接的Qt::DirectConnection
,它将等效于直接调用。如果在将两个对象中的一个移动到另一个线程之前连接好了它们(但是,当调用QObject::moveToThread
时,Qt可能会将所有连接切换到队列连接)
因此,为了直接回答,当使用排队信号时,参数会被复制,调用方的生存时间在emit
之后不再重要
我的QSharedPointer是否始终有效
只有在您将数据复制到它之后,如果是,则只要它的任何实例存在,只要您的Acquisition
类型的对象存在,它就会有效
如果在处理过程中(MainWindow),usb_read()发生了什么
记忆会写在我的图像上
竞争条件。在主窗口中处理时,您必须使用互斥锁锁定资源。智能指针本身不是线程安全的,但是QSharedPointer
使用原子整数进行引用计数,因此共享是线程安全的。同样,内容不是
在这种情况下,我的信号是否被取消,我的值是否被复制到某个地方或
线程是否正在等待我的主窗口完成处理
这取决于连接对象的方式。默认情况下,当两个qObject
位于两个不同的线程中时,连接将自动Qt::QueuedConnection
,在这种情况下,参数将首先复制(即使作为常量引用发送)在内部作为事件发布到接收方线程中。这要求参数可复制,接收方线程运行事件循环。但是,如果出于某种原因执行同一线程中默认连接的Qt::DirectConnection
,它将等效于直接调用。如果在将两个对象中的一个移动到另一个线程之前连接好了它们(但是,当调用QObject::moveToThread
时,Qt可能会将所有连接切换到队列连接)
因此,为了直接回答问题,当使用排队信号时,参数会被复制,并且调用方的生存时间在发出后不再重要,因为它已经写入了复活的答案中,只要它们至少在一个位置被引用,共享指针就有效
在您的情况下,共享指针只有一个实例,它是您在采集线程开始时创建的。它在采集线程以及将由QT调用的信号处理程序中被引用。因为您只有一个共享指针(其中有一个字节数组)现在,您正在每次采集时更新相同的数据缓冲区并覆盖它,可能是在另一个线程尚未读取它的同一时刻。但是,您可以通过为每个样本创建一个新的共享指针实例并将该实例传递给信号中的另一个线程来轻松修复该问题
下面的小改动应该可以做到这一点:
//entry point of the thread
void Acquisition::run ()
{
uint8_t* image_addr;
for (;;)
{
if (isInterruptionRequested())
return;
// here, usb_read() give me the adress of a elem in the ring buffer
img_addr = usb_read(...);
// Create a fresh shared pointer in the scope
QSharedPointer<uint8_t> image(new uint8_t[IMG_SIZE]);
// the ring buffer can possibly be rewritten on the next usb_read() (if bufferlength = 1) so I copy the data into my QSharedPointer
std::memcpy(image.data(), image_addr, sizeof(IMG_SIZE));
// I send this image
emit imageSent(image);
}
}
//线程的入口点
无效取得