Qt訊號槽的一些事

2021-09-08 19:15:13 字數 3236 閱讀 6001

注:此文是站在qt5的角度說的,對於qt4部分是不適用的。

1)qt訊號槽給出了五種連線方式:

qt::autoconnection

0自動連線:預設的方式。訊號發出的執行緒和糟的物件在乙個執行緒的時候相當於:directconnection, 如果是在不同執行緒,則相當於queuedconnection

qt::directconnection

1直接連線:相當於直接呼叫槽函式,但是當訊號發出的執行緒和槽的物件不在乙個執行緒的時候,則槽函式是在發出的訊號中執行的

qt::queuedconnection

2佇列連線:內部通過postevent實現的。不是實時呼叫的,槽函式永遠在槽函式物件所在的執行緒中執行。如果訊號引數是引用型別,則會另外複製乙份的。執行緒安全的。

qt::blockingqueuedconnection

3阻塞連線:此連線方式只能用於訊號發出的執行緒(一般是訊號物件的執行緒) 和 槽函式的物件不在乙個執行緒中才能用。通過訊號量+postevent實現的。不是實時呼叫的,槽函式永遠在槽函式物件所在的執行緒中執行。但是發出訊號後,當前執行緒會阻塞,等待槽函式執行完畢後才繼續執行。

qt::uniqueconnection

0x80

防止重複連線。如果當前訊號和槽已經連線過了,就不再連線了。

2)訊號槽的呼叫方式和執行緒:

uniqueconnection 模式:嚴格說不算連線方式,方式就是4種,此只是乙個附加的引數。不討論。

autoconnection 模式:這個模式是預設的,但其可以看作是directconnection和queuedconnection的自動選擇,直接分析那兩種也就行了。

發出訊號,呼叫槽的方式也可以簡單的分為兩種:同步呼叫和非同步呼叫

同步呼叫:發出訊號後,當前執行緒等待槽函式執行完畢後才繼續執行。

非同步呼叫:發出訊號後,立即執行剩下邏輯,不關心槽函式什麼時候執行。

所以有下表:

執行緒/模式

directconnection

queuedconnection

blockingqueuedconnection

相同執行緒

直接呼叫,同步呼叫。

通過事件進行佇列呼叫。非同步呼叫.

不可用不同執行緒

直接呼叫。同步呼叫。槽函式在發出訊號的執行緒執行。有執行緒安全隱患。

通過事件進行佇列呼叫。非同步呼叫.槽函式在物件所在的執行緒執行。執行緒安全。

通過事件進行阻塞呼叫。同步呼叫。槽函式在物件所在的執行緒執行。執行緒安全。

qt事件迴圈依賴

直接呼叫,不依賴qt事件迴圈

通過事件進行佇列呼叫。依賴,槽函式所在物件的執行緒必須啟用qt事件迴圈【注:(1)】

通過事件進行佇列呼叫,用訊號量實現阻塞。依賴,槽函式所在物件的執行緒必須啟用qt事件迴圈

先說基本原則:

槽函式開始呼叫的順序和連線的順序是一致的。

但是,上面也說了,有同步呼叫和非同步呼叫。

對於同步呼叫,你觀察的結果和基本原則一樣。

但是對於非同步呼叫,可能你最先連線的它,但是可能其他都執行完畢了,但是其還沒執行。是因為對於非同步呼叫:是開始呼叫的時候,生成乙個需要呼叫這個函式的事件,然後放到事件佇列裡。然後立即返回,去執行呼叫其他函式或者槽函式,不關心槽函式的執行狀態的。等到事件佇列裡任務輪到此事件再去呼叫。

大都說qt訊號槽不能使用返回值。其實不不準確的,qt5中,訊號槽是有返回值的(注:qt4也支援返回值)。只是qt的乙個訊號可以連線多個槽,還有同步呼叫和非同步呼叫的問題,沒法支援的很好,所以,返回值雖有,但只是雞肋。

先說下返回值的規則把:

也就是說對於queuedconnection連線的訊號槽,永遠只是返回返回型別的預設建構函式的。對於autoconnection連線的,如果發出訊號的執行緒和槽函式執行緒不同亦然。

因為乙個訊號可以連線多個槽函式,如果引數是t * 或者是t &話會不會第乙個槽函式改變引數的值,然後第二次呼叫的引數就已經不是訊號發出的值?

1)對於t &: 在同步呼叫中則是變化的,不可用於非同步,不可跨執行緒。所以blockingqueuedconnection方式的同步也不行。(t& 不可用在佇列呼叫(queuedconnection)和阻塞呼叫(blockingqueuedconnection)中。只能使用const t &

因為同步呼叫,你可以理解成直接呼叫,那麼連線多個槽函式就相當於直接連續呼叫多個函式。類似於:

//

函式原型都是:void (int &a )

inta;

fun1(a);

fun2(a)

·····

//函式原型都是:void (int * a )

inta;

pfun1(&a);

pfun2(&a)

·····

這樣,當第乙個函式執行改變引數值之後,其後的函式呼叫都要受影響。

2) 對於t *,最好不要同時連線多個槽。

對於同步呼叫:是乙個接著乙個呼叫的,執行順序類似上面,所以值也是每次呼叫也會變化的。

注:僅僅**層進行的理論分析,非實際測試,不嚴謹,不權威。

關於訊號槽(很多吐槽qt就是說的這個):

(1)qt4語法的,都說是匹配字串,其實只是鏈結訊號槽的用的匹配字串 的方法,通過字串找到訊號和槽在qmeatobject裡存的索引位置int型別,還有槽函式的索引,然後呼叫的時候通過索引號用switch去區分的 發射的那個函式,然後取出對應的鏈結槽的list,迴圈檢測槽函式的引數是否匹配,然後呼叫槽函式。。這個鏈結時會耗時查詢,但是你能有多少訊號?這個鏈 接也耗時不多,呼叫的時候耗時主要就是在引數匹配上了。

(2)qt5 語法的,qt5 的槽函式鏈結和執行是基於模板實現的,函式物件。訊號和槽的引數問題是編譯時檢查的,執行效率更高,但是編譯就慢點了。鏈結時也是通過訊號的位址找到其的 訊號索引,至於槽函式直接是生成乙個函式物件的,然後呼叫的時候也是先switch找到發射的訊號,取出list,然後逐個呼叫其儲存的函式物件,所以對 於qt5 語法的訊號槽,呼叫效能損失幾乎可以說無的。

(3)鏈結的訊號槽的時候,qt::uniqueconnection的鏈結方式會對已經鏈結過的此先好的槽函式進行遍歷,會有鏈結時的損失。其他鏈結的損失就在上面說過了。

(3)在訊號槽呼叫的時候,還有一些鏈結方式和執行緒的判斷和為了安全問題的鎖操作。關於這個就還涉及到呼叫槽函式的執行緒問題。

注:此文是個人根據文件,原始碼和自己寫小例子測試得出的總結,如有錯誤請您指出。

**:

QT的訊號和槽

qt中的訊號和槽 在圖形介面程式設計中,很多時候我們希望乙個可視物件發生某種變化時通知另乙個或幾個物件,再乙個地說,我們希望任何一類的物件能和其他物件進行通訊。例如,某個數值顯示視窗負責顯示某個滾動條物件的當前數值,當滾動條物件的值發生變化時,我們希望數值顯示視窗能收到來自滾動條物件傳送的 數值改變...

QT的訊號與槽

乙個訊號可以與多個槽建立連線 connect spinnum,signal valuechanged int this,slot addfun int connect spinnum,signal valuechanged int this,slot updatestatus int 這時,槽函式按...

Qt學習(一 Qt簡介,訊號和槽)

選擇位置,選擇構建套件 選擇類的資訊,其中 基類 有三種選擇。其他兩個是qwidget的子類。有兩種方式建立圖形介面 拖拽。點選完成,會生成幾個檔案。原始檔和標頭檔案。還有乙個 pro 檔案。其中 pro為工程檔案。main.cpp 程式的入口 include widget.h 包含乙個應用程式類的...