Qt跨執行緒傳送訊號與元資料

2021-08-04 22:47:31 字數 2657 閱讀 1265

熟悉多執行緒的讀者應該都感受到這裡會有乙個微妙的問題。如果signals/slots的函式引數是乙個自己定義的型別。比如自己定義了乙個student類,訊號函式為sendstudent(const student &stu); 對應的槽函式為:getstudent(const student &stu); 如果在非主線程使用emit發射訊號的時候,student引數是乙個臨時變數的話(即可能馬上被析構掉),那麼主線程在執行這個槽函式的時候這個臨時變數可能被析構了。這就相當於使用了野指標。

qt的作者肯定也想到了這一點。

我們回過頭來深入了解connect函式,因為是它把訊號和槽連起來的。在connect函式中,我們一般都只使用4個引數。實際上它是有5個引數的,只是使用了預設引數而已。第5個引數是乙個列舉型別qt::connectiontype,有下面5種:

從上面的關聯型別可以知道:qt的作者是有考慮到發射訊號的執行緒不是執行槽函式的執行緒。那麼qt是怎麼解決剛才那個微妙的問題的呢?答案是元資料。在呼叫connect的前面呼叫qregistermetatype("student");把這個student型別註冊成元資料。這樣就能避免那個問題了。

由於我沒有閱讀qt的源**,不知道qt內部具體是怎麼實現的。我把qt的實現當作乙個黑盒子,通過一些文件和測試進行一些猜想。下面就是我的猜想,不一定正確。

假如這個微妙的問題給我們自己來解決,那麼很容易想到的方法是:在內部複製乙個student類。這樣無論發射執行緒的臨時student是否被析構都無所謂了。

通過閱讀qt助手的qregistermetatype詞條,會發現把乙個型別註冊成元資料是有條件的:這個型別要提供public屬性的預設建構函式、複製建構函式、析構函式。這應該是為了複製乙個student吧。嘿嘿。下面通過乙個例子驗證之。

標頭檔案:

[cpp]view plain

copy

#ifndef tk_hpp

#define tk_hpp

#include

#include

#include

class

student  

student(const

qstring &name, 

const

qstring &id)  

:m_name(name), m_id(id)  

{}  

student(const

student& stu)  

qstring name()const

void

name(

const

qstring& name)   

private

:  qstring m_name;  

qstring m_id;  

};  

class

test : 

public

qobject  

private

slots:  

void

getstu(

const

student &stu)  

public

:  void

printstu(

const

student& stu)  

private

:  signals:  

void

sendstu(

const

student& stu);  

};  

class

mythread : 

public

qthread  

protected

:  void

run()  

private

:  test *m_test;  

};  

#endif // tk_hpp

原始檔:

[cpp]view plain

copy

#include"tk.hpp"

intmain(

intargc, 

char

*argv)    

執行輸出為:

可以看到,qt果然是複製錯誤了。

如果刪除student中的複製建構函式(此時使用編譯器提供的預設複製建構函式),那麼輸出就會為:

可以看到,qt內部已經複製了乙份student,所以即使次執行緒修改了student的name,也不影響。

如果在test的建構函式中,刪除qregistermetatype("student")。那麼在執行時候就會出現:

估計qt在emit的實現裡面會判斷發出訊號的執行緒是否為主執行緒。如果不是的話,那麼就檢測signals/slots的引數是否為乙個元資料。如果不是的話那麼就拒絕傳送訊號。非元資料是不安全的。

對於c/c++的基本型別和qt定義的類,都不用我們手動將之註冊為元資料了。qt已經幫我們幹了這些事情。

pthread kill 向執行緒傳送訊號

別被名字嚇到,pthread kill可不是kill,而是向執行緒傳送signal。還記得signal嗎,大部分signal的預設動作是終止程序的執行,所以,我們才要用signal 去抓訊號並加上處理函式。int pthread kill pthread t thread,int sig 向指定id...

Qt如果傳送訊號過快會如何?

在事件迴圈中會發生什麼?訊號是否會堆積直到它們都執行完 100s 是否有丟棄事件的機制?使用者事件永遠不會丟棄。如果傳送訊號過快超過處理時間,時間會排隊指導耗盡記憶體而程式崩潰。然而,qtimer在負載過重時會跳過超時事件。這在某種程度上調節了負載。你可以從乙個消費者執行緒中傳送反饋 比如通知 給生...

QT訊號槽的跨執行緒連線

qt中的執行緒可以通過繼承qthread類,重寫run 函式,run 函式即新執行緒的入 通過start 函式啟動新執行緒 我我們實現的這個qthread的派生類,只不過是用來管理執行緒的。run 函式返回,新執行緒結束,可以在呼叫 exec 函式,在新執行緒中也開啟時間迴圈。繼承自qobject的...