QSharedPointer 或 std::shared_ptr 的生命周期
life cycle of QSharedPointer or std::shared_ptr
在我的应用程序中
我有一个MainWindow
(这是一个QtMainWindow
类)和一个Acquisiton
类(这是一个QThread
类)
在这里,我非常简化的Acquisiton类
//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);
}
}
在我的主窗口中,我已经
// the slot for the signal imageSent
void newImage(QSharedPointer<uint8_t> image)
{
// process and draw image
}
我不了解QSharedPointer (和 std::shared_ptr 的生命周期(想象一下与 std::shared_ptr 相同的代码)
我的QSharedPointer 总是有效的吗? 如果在处理(主窗口)期间,usb_read()发生并且memcpy写入我的图像,则附加什么。
在相关问题中:在退出之前等待执行插槽
我看到如果采集线程在数据处理期间停止,QSharedPointer 将保持我的数据有效。
在这种情况下,我的信号是否被取消,我的值是否被复制到某处,或者线程等待我的 MainWindow 完成处理?
谢谢
正如在复活的答案中已经写的那样,只要至少在一个位置引用共享指针,它们就有效。
在您的情况下,您将只有一次共享指针的实例,即您在获取线程开始时创建的那个实例。它在采集线程以及将由 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等)时,数据将被取消排队,信号处理程序将被调用。
我的 QSharedPointer 总是有效的吗?
只有在您将数据复制到其中之后,但在那之后是的,只要它的任何实例存在,只要您的类型Acquisition
对象存在,它就会有效。
如果在处理(主窗口)期间发生usb_read()发生,则追加什么 和记忆写在我的图像上。
争用条件。在MainWindow
中处理时,您必须使用互斥锁来锁定资源。智能指针本质上不是线程安全的,但是QSharedPointer
使用原子整数进行引用计数,因此共享是线程安全的。同样,内容不是!
信号是否被取消,我的值是否被复制到某个地方或 线程等待我的主窗口完成处理?
这取决于您连接对象的方式。默认情况下,当两个QObjects
存在于两个不同的线程中时,连接会自动Qt::QueuedConnection
在这种情况下,参数首先在内部复制(即使作为 const 引用发送)以作为事件发布到接收方的线程中。这要求参数是可复制的,并且接收方的线程运行事件循环。但是,如果您出于某种原因Qt::DirectConnection
这是同一线程中连接的默认方法,则等同于直接调用。如果您在将其中一个对象移动到另一个线程之前连接了这两个对象,则可能会发生这种情况(但是,当调用 Qt 时,Qt 可能会将所有连接切换到排队的连接QObject::moveToThread
)。
因此,要直接回答,当使用排队信号时,参数被复制,并且在emit
之后调用者的生命周期不再重要。
- 如何在共享库的整个生命周期内存储数据
- 如何理解句子的生命周期始于对e的评估
- 它解决了什么问题,对于非真空初始化,生命周期在初始化之前就开始了
- Go/C++gRPC客户端通道和存根生命周期
- 如何将"this"的生命周期移动到C++中的另一个对象中?
- 是否可以通过使用移动/交换 c++11 来延长返回的临时变量的生命周期
- 使用对象的生命周期作为设置器的安全性
- 临时人员的生命周期传递给函数
- 我想知道在构造函数中初始化变量时的生命周期
- Lua 用户数据生命周期管理
- 如何使用 epoll(void* event.data.ptr) 管理 Connection 的生命周期
- C++引用的生命周期
- 在堆栈上有一个对象,而不是在函数的整个生命周期内
- 在 Boost ASIO 服务器中处理生命周期
- C++ lambda 生命周期
- 使用互斥锁跟踪另一个应用的生命周期
- QSharedPointer 或 std::shared_ptr 的生命周期
- 来自async_resolve的 boost::asio::ip::tcp::resolver::iterator 的生命周期是多久?
- 如何调整属于类的唯一指针的字符数组的大小.它必须在程序的整个生命周期中保持活力
- 延长 std::tuple<int&,int> 的生命周期,方法是将其分配给 const std::tuple<int, int>&