Qt 多線程中的信號/槽


 

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文件。

  2 一個很清晰明了的例子

  3 既然線程對象本身是屬於父線程的,為何在run函數中使用對象的成員不會出現跨線程- -!是說qthread對象本身就可以跨線程訪問么。。不明白


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM