[英]life cycle of QSharedPointer or std::shared_ptr
在我的申请中
我有一个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);
}
}
在我的MainWindow中
// the slot for the signal imageSent
void newImage(QSharedPointer<uint8_t> image)
{
// process and draw image
}
我不了解QSharedPointer(和std :: shared_ptr的生命周期)(想象与std :: shared_ptr相同的代码)
我的QSharedPointer是否一直有效? 如果在处理(MainWindow)期间出现usb_read()并将memcpy写在我的图像上,该追加什么内容。
在一个相关的问题中: 退出前要执行等待的插槽
我看到,如果在数据处理期间停止了获取线程,则QSharedPointer会使我的数据保持有效。
在这种情况下,是否取消了我的信号,将我的值复制到了某个地方,还是线程等待我的MainWindow完成处理?
谢谢
我的QSharedPointer是否一直有效?
仅在将数据复制到数据之后,然后再复制,只要它的任何实例存在,只要您的类型为Acquisition
的对象存在,它就将是有效的。
如果在处理(MainWindow)期间出现usb_read()并将memcpy写在我的图像上,该追加什么内容。
比赛条件。 在MainWindow
处理时,必须使用互斥锁来锁定资源。 智能指针本质上不是线程安全的,但是QSharedPointer
使用原子整数进行引用计数,因此共享是线程安全的。 再次,内容不是!
在这种情况下,是否取消了我的信号,将我的值复制到了某个地方,还是线程等待我的MainWindow完成处理?
这取决于您如何连接对象。 默认情况下,当两个QObjects
位于两个不同的线程中时,连接将自动为Qt::QueuedConnection
,在这种情况下,将首先在内部复制参数(即使作为const引用发送),然后将其作为事件发布到接收者的线程中。 这要求参数是可复制的,并且接收者的线程正在运行事件循环。 但是,如果由于某种原因执行Qt::DirectConnection
这是默认情况下在同一线程中进行连接),则等效于直接调用。 如果您在将两个对象中的一个移到另一个线程之前已经连接了两个对象,则可能会发生这种情况(但是,当调用QObject::moveToThread
时,Qt可能QObject::moveToThread
所有连接都切换到排队的QObject::moveToThread
)。
因此,直接回答是,当使用排队信号时,将复制参数,并且emit
之后,调用方的寿命不再重要。
正如它已经写在复活的答案中一样,共享指针只要至少在一个位置被引用就有效。
在您的情况下,共享指针将只有一个实例,这是您在Acquisition线程开始时创建的实例。 它在Acquisition线程以及将由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);
}
}
关于取消和信令:当您调用QT中不同线程之间的发射信号时,默认情况下将使用排队连接。 这意味着在发出线程上,应将数据和应调用的处理程序放入队列中。 此处的数据是您的共享指针。 即使获取线程完成,该队列也将保持活动状态。 然后,当另一个线程踢入(MainThread等)时,数据将出队,并随之调用信号处理程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.