connect函數的五個參數表示的意義依次為:sender*, signal, receiver*, slot,connectionTpye
其中槽可以是receiver的成員函數,或者是任意可訪問的靜態函數。在多線程的情形下:
1. 一個對象的線程就是創建該對象時的線程,而不論該對象的定義是保存在那個線程中;
比如在thread1中開了個新線程thread2,那么thread2 對象就是定義在thread1中的,即thread2對象本身是屬於thread1的,而在thread2的run函數中定義的對象則是屬於thread2的。
2. QObject的connect函數有幾種連接方式,
a) DirectConnection,信號發送后槽函數立即執行,由sender的所在線程執行;
b) QueuedConnection,信號發送后返回,相關槽函數由receiver所在的線程在返回到事件循環后執行;
c) 默認使用的是Qt::AutoConnection,當sender和receiver在同一個線程內時,采用DirectConnection的方式,當sender和receiver在不同的線程時,采用QueuedConnection的方式。
所以如果發生了跨線程調用,即在線程a中使用了線程b的對象就會報各種錯誤,如:
Cannot create children for a parent that is in a different thread
QSocketNotifier: socket notifiers cannot be enabled from another thread
Assert failure:Cannot send events toobjects owned by a different thread
產生這個問題的原因就是因為sender跟receiver可能是屬於不同的線程,可能會導致發出信號的線程與接收信號執行槽函數的線程不同。比如sender發出信號x,讓槽函數處理一下某些數據,這些數據顯然跟sender是在一個線程的,但執行槽函數的時候線程切換了,就等於在處理別的線程的數據了。
解決辦法有:
1,采用直接連接方式,讓槽函數在發出信號的對象所依賴的線程中執行,也就是不讓信號進入消息隊列,直接處理,但是這樣貌似需要對線程同步進行處理。
2,將receiver移動至sender的線程,比如在thread1中創建了一個thread2,在thread2的run函數中創建了一個obj。想讓obj發出信號,然后thread2對象來處理,那么在創建thread2之后把thread2用moveToThread(thread2)移動到thread2中即可,這樣sender跟receiver就在同一個線程中了,不過拘束不推薦這么做
3,文檔中推薦的方法為:在run函數中創建一個對象,這個對象肯定是屬於thread2的,然后使用thread2作為revcever來處理信號即可
PS:
1 遇見各種亂起八糟的連接問題,可以make clear把各種.o什么的刪了重新編譯,或者刪掉自動生成的makfile,或者檢查pro文件。
3 既然線程對象本身是屬於父線程的,為何在run函數中使用對象的成員不會出現跨線程- -!是說qthread對象本身就可以跨線程訪問么。。不明白