QThread 繼承 QObject 。它發射指示綫程啓動 (或執行完成) 的信號,且還提供瞭幾個槽。
更有趣的是 QObject 可以用於多綫程,發射援引其它綫程槽的信號,並把事件張貼給 "存活" 於其它綫程中的對象。這是可能的,因為每個綫程都允許擁有它自己的事件循環。
QObject 可重入。它的大多數非 GUI (圖形用戶界麵) 子類,譬如 QTimer , QTcpSocket , QUdpSocket and QProcess ,也可重入,使之可能從多綫程同時使用這些類。注意,設計是從單綫程創建和使用這些類;在某個綫程中創建對象並從另一綫程調用其函數,不能保證能工作。要注意存在 3 個約束:
this
) 作為在綫程中創建對象的父級 (由於
QThread
對象自身是在另一綫程中創建的)。
盡管 QObject 是可重入 GUI 類,顯而易見 QWidget 及其所有子類,都不可重入。隻可以從主綫程使用它們。如前所述, QCoreApplication::exec () 還必須從該綫程調用。
在實踐中,不可能在主綫程外的其它綫程中使用 GUI (圖形用戶界麵) 類,通過把耗時操作放入單獨工作者綫程,並在工作綫程完成時在主綫程屏幕中顯示結果,可輕鬆解決。此實現方式可以用於 Mandelbrot 範例 和 阻塞 Fortune 客戶端範例 .
一般而言,創建 QObject 先於 QApplication 不支持,且退齣時可能導緻奇怪崩潰,從屬平颱。這意味著靜態實例 QObject 也不支持。結構閤理的單 (或多) 綫程應用程序應該使 QApplication 被首先創造,且最後銷毀 QObject .
每個綫程都可以擁有它自己的事件循環。初始綫程啓動其事件循環是使用 QCoreApplication::exec (),或對於單對話框 GUI (圖形用戶界麵) 應用程序,有時是 QDialog::exec ()。其它綫程啓動事件循環可以使用 QThread::exec ()。像 QCoreApplication , QThread 提供 exit (int) 函數和 quit() 槽。
綫程中的事件循環使之可能對要使用某些非 GUI Qt 類的綫程,要求存在事件循環 (譬如 QTimer , QTcpSocket ,和 QProcess )。還使之可能把來自任何綫程的信號,連接到特定綫程槽。闡述這的更多細節在 信號和槽跨綫程 以下章節。
A QObject 實例據稱是 live 在創建它的綫程中。此對象的事件由該綫程的事件循環分派。綫程對於 QObject 存活的獲得是使用 QObject::thread ().
The QObject::moveToThread () 函數改變對象,及其子級的綫程親緣關係 (對象無法移動,若它擁有父級)。
調用
delete
在
QObject
從綫程而不是某個綫程其
owns
對象 (或以其它方式訪問對象) 是不安全的,除非保證對象在那刻不處理事件。使用
QObject::deleteLater
() 代替,和
DeferredDelete
事件將被張貼,最終將拾取對象綫程的事件循環。默認情況下,綫程
owns
a
QObject
是綫程
creates
the
QObject
,但不後於
QObject::moveToThread
() 被調用。
若沒有事件循環在運行,就不會將事件交付給對象。例如,若創建 QTimer 對象在綫程,但從不調用 exec() , QTimer 將從不發射其 timeout() 信號。調用 deleteLater() 也不會工作 (這些限定也適用於主綫程)。
可以在任何時間手動將事件張貼給任何綫程中的任何對象,使用綫程安全函數 QCoreApplication::postEvent ()。將通過創建對象綫程的事件循環,自動分派事件。
支持事件過濾器的所有綫程,具有監視對象必須活在如被監視對象的同一綫程中的限定。同樣, QCoreApplication::sendEvent () (不像 postEvent() ) 隻可以用於把事件分派給活在從那裏調用函數的綫程中的對象。
QObject 及其所有子類都不是綫程安全的。這包括整個事件交付係統。它很重要,記住事件循環可能把事件交付給 QObject 子類,當從另一綫程訪問對象時。
若正調用函數在 QObject 子類未活在當前綫程中且對象可能接收事件,就必須保護所有訪問對 QObject 子類的內部數據按互斥;否則,可能經曆崩潰 (或其它不期望行為)。
像其它對象, QThread 對象活在創建對象的綫程中 -- not 在創建綫程中,當 QThread::run () 被調用。提供槽通常不安全在 QThread 子類,除非采用互斥保護成員變量。
另一方麵,可以安全地發射信號從 QThread::run () 實現,因為信號發齣是綫程安全的。
Qt 支持這些信號/槽連接類型:
注意: 使用這種類型連接同一綫程中的對象,會導緻死鎖。
false
.
可以指定連接類型,通過把額外自變量傳遞給 connect() 。要意識到,當發送者和接收者活在不同綫程中時 (若事件循環運行在接收者綫程中) 使用直接連接不安全,齣於相同原因,調用活在另一綫程中對象的任何函數也不安全。
QObject::connect () 本身是綫程安全的。
The Mandelbrot 範例 使用 "隊列連接" 進行通信,在工作者綫程和主綫程之間。為避免凍結主綫程的事件循環 (並因此,凍結應用程序的用戶界麵),所有 Mandelbrot 分形計算都是在單獨工作者綫程中完成。綫程發射信號,當分形渲染完成時。
同樣, 阻塞 Fortune 客戶端範例 使用單獨綫程與 TCP 服務器進行異步通信。