熟悉多執行緒的讀者應該都感受到這裡會有乙個微妙的問題。如果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的...