[英]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.