QThread 繼承 QObject 。它發射指示綫程啓動 (或執行完成) 的信號,且還提供瞭幾個槽。
更有趣的是 QObject 可以用於多綫程,發射援引其它綫程槽的信號,並把事件張貼給 "存活" 於其它綫程中的對象。這是可能的,因為每個綫程都允許擁有它自己的事件循環。
QObject 可重入。它的大多數非 GUI (圖形用戶界麵) 子類,譬如 QTimer , QTcpSocket , QUdpSocket and QProcess ,也可重入,使之可能從多綫程同時使用這些類。注意,設計是從單綫程創建和使用這些類;在某個綫程中創建對象並從另一綫程調用其函數,不能保證能工作。要注意存在 3 個約束:
this
) 作為在綫程中創建對象的父級 (由於
QThread
對象自身是在另一綫程中創建的)。
盡管 QObject 是可重入 GUI 類,顯而易見 QWidget 及其所有子類,都不可重入。隻可以從主綫程使用它們。如前所述, QCoreApplication::exec () 還必須從該綫程調用。
在實踐中,不可能在主綫程外的其它綫程中使用 GUI (圖形用戶界麵) 類,通過把耗時操作放入單獨工作者綫程,並在工作綫程完成時在主綫程屏幕中顯示結果,可輕鬆解決。此實現方式可以用於 Mandelbrot 範例 和 Blocking Fortune Client example .
一般而言,創建 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 () signal. Calling deleteLater () won't work either. (These restrictions apply to the main thread as well.)
可以在任何時間手動將事件張貼給任何綫程中的任何對象,使用綫程安全函數 QCoreApplication::postEvent ()。將通過創建對象綫程的事件循環,自動分派事件。
支持事件過濾器的所有綫程,具有監視對象必須活在如被監視對象的同一綫程中的限定。同樣, QCoreApplication::sendEvent () (不像 postEvent ()) can only be used to dispatch events to objects living in the thread from which the function is called.
QObject 及其所有子類都不是綫程安全的。這包括整個事件交付係統。它很重要,記住事件循環可能把事件交付給 QObject 子類,當從另一綫程訪問對象時。
若正調用函數在 QObject 子類未活在當前綫程中且對象可能接收事件,就必須保護所有訪問對 QObject 子類的內部數據按互斥;否則,可能經曆崩潰 (或其它不期望行為)。
像其它對象, QThread objects live in the thread where the object was created – not 在創建綫程中,當 QThread::run () 被調用。提供槽通常不安全在 QThread 子類,除非采用互斥保護成員變量。
另一方麵,可以安全地發射信號從 QThread::run () 實現,因為信號發齣是綫程安全的。
Qt 支持這些信號/槽連接類型:
注意: 使用這種類型連接同一綫程中的對象,會導緻死鎖。
false
.
可以指定連接類型,通過把額外自變量傳遞給 connect (). Be aware that using direct connections when the sender and receiver live in different threads is unsafe if an event loop is running in the receiver's thread, for the same reason that calling any function on an object living in another thread is unsafe.
QObject::connect () 本身是綫程安全的。
The Mandelbrot 範例 使用 "隊列連接" 進行通信,在工作者綫程和主綫程之間。為避免凍結主綫程的事件循環 (並因此,凍結應用程序的用戶界麵),所有 Mandelbrot 分形計算都是在單獨工作者綫程中完成。綫程發射信號,當分形渲染完成時。
同樣, Blocking Fortune Client example 使用單獨綫程與 TCP 服務器進行異步通信。