QT中的執行緒QThread

2021-07-09 21:57:25 字數 4071 閱讀 3719

譯文如下:

class worker : public qobject

signals:

void resultready(const qstring &result);

};class controller : public qobject

~controller()

public slots:

void handleresults(const qstring &);

signals:

void operate(const qstring &);

};

在worker的slot中的**將在乙個單獨的執行緒中執行。但是,你可以將worker的slots和任何執行緒的任何物件的任何signal進行連線。連線不同執行緒中的signal和slot是安全的,這是由於"queued connections"機制。(注:該連線型別指的是,一旦當cpu的控制權回到接收者執行緒的event loop後就會呼叫slot函式)

還有一種方法可以使**執行在另乙個執行緒中。這就是繼承qthread類,並重新實現run()函式。**示例如下:

class workerthread : public qthread

signals:

void resultready(const qstring &s);

};void myobject::startworkinathread()

在以上的例子中,執行緒將在run()函式結束執行後退出。在此執行緒中不會有event loop,除非呼叫了exec(). 

注意,乙個qthread例項是存在於(lives in)老執行緒(即初始化該例項的執行緒)中的,而不是存在於新的呼叫run()的執行緒中的。這就是說,所有qthread的queued slots都將在老執行緒中被執行。因此,如果希望在新執行緒中呼叫slots函式,就必須使用worker-object的方法(譯註:應該指上面第二種方法);新slots函式不應該在qthread子類中直接實現。

當繼承qthread類時,記住,建構函式在老執行緒中執行,而run()在新執行緒中執行。如果乙個成員變數被2個函式都訪問,那麼這個變數就是被2個不同的執行緒在訪問。要檢查這麼做是否安全。

附: int qthread::exec()

進入event loop並等待直到exit()被呼叫,返回傳遞給exit()的值。如果exit()是通過quit()被呼叫的,那麼該返回值就是0. 

這個方法一般是在run()函式中被呼叫的。啟動event handling就必須要呼叫此方法。

當執行緒是started()或finished(),qthread會通過乙個signal來通知你,或者你可以使用isfinished()和isrunning()來檢查執行緒的狀態。

可以通過呼叫exit()和quit()來結束執行緒。在極端情況下,可以使用terminate()強制結束乙個正在執行的執行緒。但是,這麼做是危險的和不推薦的。請閱讀關於terminate()和setterminationenabled()的文件。

qt4.8及以後,通過連線finished() signal和qobject::deletelater(),可以釋放在乙個執行緒中剛剛結束的物件。

使用wait()來阻塞正在被呼叫的執行緒,直到其他執行緒結束了執行(或特定時間超時)。

qthread也提供靜態的,平台無關的sleep函式,如sleep(), msleep(), 和usleep()來允許秒級,毫秒級,微秒級的休眠。這些函式直到qt5.0才成為public的。

注意,wait()和sleep()函式一般應該是不必要的,因為qt是乙個事件驅動的框架。可以考慮以監聽finished() signal來代替wait(),而使用qtimer來代替sleep()函式。

靜態函式currentthreadid()和currentthread()返回當前執行緒的id. 前者返回乙個平台相關的id,而後者返回乙個qthread指標。

為了選擇你的執行緒的名字(如同在linux上執行"ps -l"命令所顯示的),你可以在啟動執行緒之前呼叫setobjectname(). 如果不呼叫setobjectname(),執行緒的名字將是你的執行緒物件執行時型別的類名(比如,對於manderbrot example,"renderthread"就是執行緒名)。注意,在windows系統上,這個是目前不支援的。

乙個qobject物件是有執行緒關聯性的,或者說它是存在於某特定執行緒中的。當乙個qobject物件接收到乙個queued signal或者乙個被傳送來的event時,對應的slot函式或event handler就會在該物件所在的執行緒中執行。

注意: 如果乙個qobject物件沒有執行緒關聯性(也就是說,如果thread()函式返回0),或者它所存在的執行緒沒有event loop,那麼它就無法接收queued signal或posted events. 

預設情況下,qobject物件存在於它被建立的那個執行緒中。可以使用thread()函式來查詢乙個物件的執行緒關聯性,而用movetothread()來改變乙個物件的執行緒關聯。

所有qobjects都必須存在於和它們的父親所在的執行緒中。因此:

注意:乙個qobject物件的成員變數不能夠自動程式設計該物件的孩子。父子關係的建立只能通過給孩子的建構函式傳遞乙個指標,或者是呼叫setparent(). 沒有這一步,即使呼叫了movetothread(),該物件的成員變數將繼續儲存在老執行緒中。

為了同步執行緒,qt提供了底層的原語和上層的機制。

qmutex是強制互斥的基礎類。

qreadwritelock和qmutex類似,不同的是它會區分讀訪問和寫訪問。當一段資料並沒有被寫的時候,多個執行緒同時去讀取它是安全的。而qmutex在此種情況下仍會強制多個讀執行緒序列去讀。因為qreadwritelock允許同時讀,所以它更高效。

qsemaphore是對qmutex的泛化。qmutex只保護乙個資源,而qsemaphore保護一定數量的資源。

qwaitcondition並不通過強制互斥而是通過條件變數來實現執行緒同步。qwaitcondition使得執行緒一直等待,直到乙個特定條件滿足。為了允許在waiting的執行緒繼續工作,呼叫wakeone()可以隨機喚醒乙個正在等待的執行緒;而wakeall()則將所有等待的執行緒都喚醒。wait conditions example給出了如何通過qwaitcondition來解決生產者消費者問題。

注意:qt的執行緒同步類依賴於正確對齊的指標的使用。比如,用msvc你就無法使用緊湊型的類(packed classes)。

這些同步類可以使得乙個方法執行緒安全。但是,這麼做也會影響效能,這就是為什麼大多數qt的方法並不是執行緒安全的。

如果乙個執行緒鎖住了乙個資源而沒有釋放它,那麼整個應用就會凍結住,因為所有其他執行緒都永遠無法獲得該資源。這是可能的,比如,如果丟擲了乙個異常並迫使當前函式沒有釋放鎖就返回了。

另乙個類似的場景是死鎖。比如,假設2個執行緒各自等待對方所持有的乙個資源,那麼就會陷入死鎖,而應用就會凍結住。

qmutexlocker、qreadlocker和qwritelocker是方便的類。利用它們可以更加容易地使用qmutex和qreadwritelock. 它們在構造的時候鎖住乙個資源,而當它們銷毀的時候會自動釋放資源。它們被設計用來簡化使用qmutex和qreadwritelock的**,因此減少了使得乙個資源被永遠鎖住的可能。

qt的event system對於執行緒間通訊非常有用。每個執行緒都可能有它自己的event loop. 為了在另乙個執行緒中呼叫乙個slot(或任何可以被呼叫的方法),把呼叫放在目標執行緒的event loop中。這使得目標執行緒在完成它當前的任務後就去執行slot函式,而原來的執行緒將繼續並行地執行。

為了在乙個event loop中進行呼叫,要進行queued signal-slot連線。無論該signal在何時被發射,它的引數將被event system記錄下來。接收者所在的執行緒將執行該slot函式。或者,呼叫qmetaobject::invokemethod()來達到同樣的效果而無需使用signals. 在這2種情況下,乙個queued connection必須被使用,因為乙個direct connection繞過了event system,使得該方法在當前執行緒中被立即執行。

和底層原語不同,當使用event system來進行執行緒同步的時候,沒有發生死鎖的風險。但是event system並沒有進行互斥。如果被呼叫的方法訪問共享資料的時候,共享資料的訪問必須被底層原語保護。

Qt多執行緒開發 QThread

件 class mythread public qthread mythread virtual void run cpp檔案 void mythread run 件 class mythread public qthread mythread virtual void run class move...

QT多執行緒(QThread)小結

qthread只有run函式是在新執行緒裡的,其他所有函式都在qthread生成的執行緒裡 如果qthread是在ui所在的執行緒裡生成,那麼qthread的其他非run函式都是和ui執行緒一樣的,所以,qthread的繼承類的其他函式盡量別要有太耗時的操作,要確保所有耗時的操作都在run函式裡。在...

Qthread執行緒修改UI

from pyqt5.qtcore import from pyqt5.qtgui import from pyqt5.qtwidgets import import time 訊號傳參型別 pyqtsignal 無引數訊號 pyqtsignal int 乙個引數 整數 的訊號 pyqtsignal...