久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

解析Qt中QThread使用方法

 guitarhua 2012-02-18

解析Qt中QThread使用方法(1)

2011-06-14 10:18 佚名 互聯(lián)網(wǎng) 我要評論(0) 字號:T | T
一鍵收藏,,隨時查看,,分享好友,!

本文介紹了Qt中QThread使用方法,,在本片文章中反復(fù)提到了線程的使用,,詳細(xì)內(nèi)容請參考本文,QThread的使用方法:#include 繼承了Qt,。

AD:

本文講述的是在QtQThread使用方法,,QThread似乎是很難的一個東西,特別是信號和槽,,有非常多的人(盡管使用者本人往往不知道)在用不恰當(dāng)(甚至錯誤)的方式在使用 QThread,,隨便用google一搜,就能搜出大量結(jié)果出來,。無怪乎Qt的開發(fā)人員 Bradley T. Hughes 聲嘶力竭地喊you are-doing-it-wrong

和眾多用戶一樣,,初次看到這個時,感到 Bradley T. Hughes有 些莫名奇妙,,小題大作,。盡管不舒服,當(dāng)時還是整理過一篇博客QThread 的使用方法

時間過去3個月,,盡管依然沒怎么用thread,;但今天csdn論壇中有人問到這個問題,想想還是盡我所能整理一下吧,。提升自己,方便他人,,何樂而不為呢?

QThread東西還是比較多的,,而且我對底層對象了解有限,,僅就一點進行展開(或許是大家最關(guān)心的一點):QThread中的slots在那個線程中執(zhí)行?

QThread::run

run 函數(shù)是做什么用的,?Manual中說的清楚:

run 對于線程的作用相當(dāng)于main函數(shù)對于應(yīng)用程序,。它是線程的入口,run的開始和結(jié)束意味著線程的開始和結(jié)束,。 原文如下:

  1. The run() implementation is for a thread what the main()   
  2. entry point is for the application. All code executed in a call stack that starts in the run()   
  3. function is executed by the new thread, and the thread finishes when the function returns.  

這么短的文字一眼就看完了,,可是,這是什么意思呢,?又能說明什么問題呢,?看段簡單代碼:

  1. class Thread:public QThread {       
  2. Q_OBJECT public:       
  3. Thread(QObject* parent=0):QThread(parent){}   
  4. public slots:       
  5. void slot() { ... } signals:       
  6. void sig(); protected:       
  7. void run() { ...} };    
  8. int main(int argc, char** argv) { ...     Thread thread; ... } 

對照前面的定理,run函數(shù)中的代碼時確定無疑要在次線程中運行的,,那么其他的呢,?比如 slot 是在次線程還是主線程中運行?

QObject::connect

涉及信號槽,,我們就躲不過 connect 函數(shù),,只是這個函數(shù)大家太熟悉。我不好意思再用一堆廢話來描述它,,但不說又不行,,那么折中一下,只看它的最后一個參數(shù)吧(為了簡單起見,,只看它最常用的3個值):

1,、自動連接(Auto Connection)

這是默認(rèn)設(shè)置

如果發(fā)送者和接收者處于同一線程,則等同于直接連接

如果發(fā)送者和接受者位于不同線程,,則等同于隊列連接

也就是這說,,只存在下面兩種情況

2、直接連接(Direct Connection)

當(dāng)信號發(fā)射時,,槽函數(shù)將直接被調(diào)用,。

無論槽函數(shù)所屬對象在哪個線程,槽函數(shù)都在發(fā)射者所在線程執(zhí)行,。

3,、隊列連接(Queued Connection)

當(dāng)控制權(quán)回到接受者所在線程的事件循環(huán)式,槽函數(shù)被調(diào)用,。

槽函數(shù)在接收者所在線程執(zhí)行,。

同前面一樣,這些文字大家都能看懂,。但含義呢,?

不妨繼續(xù)拿前面的例子來看,slot 函數(shù)是在主線程還是次線程中執(zhí)行呢,?

定理二強調(diào)兩個概念:發(fā)送者所在線程 和 接收者所在線程,。而 slot 函數(shù)屬于我們在main中創(chuàng)建的對象 thread,,即thread屬于主線程

隊列連接告訴我們:槽函數(shù)在接受者所在線程執(zhí)行。即 slot 將在主線程執(zhí)行

直接連接告訴我們:槽函數(shù)在發(fā)送者所在線程執(zhí)行,。發(fā)送者在那個線程呢,??不定,!

自動連接告訴我們:二者不在同一線程時,,等同于隊列連接。即 slot 在主線程執(zhí)行

要徹底理解這幾句話,,你可能需要看Qt meta-object系統(tǒng)和Qt event系統(tǒng))

如果上兩節(jié)看不懂,,就記住下面的話吧(自己總結(jié)的,用詞上估計會不太準(zhǔn)確),。

QThread 是用來管理線程的,,它所處的線程和它管理的線程并不是同一個東西

QThread 所處的線程,就是執(zhí)行 QThread t(0) 或 QThread * t=new QThread(0) 的線程,。也就是咱們這兒的主線程

QThread 管理的線程,,就是 run 啟動的線程。也就是次線程

因為QThread的對象在主線程中,,所以他的slot函數(shù)會在主線程中執(zhí)行,,而不是次線程。除非:QThread 對象在次線程中

slot 和信號是直接連接,,且信號所屬對象在次線程中

但上兩種解決方法都不好,,因為QThread不是這么用的(Bradley T. Hughes)

好了,不在添加更多文字了,,看代碼,,估計咱們都會輕松點

主線程(信號)QThread(槽)

這是Qt Manual 和 例子中普遍采用的方法。 但由于manual沒說槽函數(shù)是在主線程執(zhí)行的,,所以不少人都認(rèn)為它應(yīng)該是在次線程執(zhí)行了,。

定義一個 Dummy 類,用來發(fā)信號

定義一個 Thread 類,,用來接收信號

重載 run 函數(shù),,目的是打印 threadid

  1. /*!  
  2. * \file main.cpp  
  3. *  
  4. * Copyright (C) 2010, dbzhang800  
  5. * All rights reserved.  
  6. *  
  7. */  
  8. #include <QtCore/QCoreApplication>   
  9. #include <QtCore/QObject>   
  10. #include <QtCore/QThread>   
  11. #include <QtCore/QDebug>  class Dummy:public QObject {       
  12. Q_OBJECT public:     
  13. Dummy(){} public slots:  void emitsig()   
  14. {         emit sig();       
  15. } signals:     void sig();   
  16. };    
  17. class Thread:public QThread {      
  18.  Q_OBJECT public:       
  19. Thread(QObject* parent=0):QThread(parent) {   //moveToThread(this); }   
  20. public slots:     void slot_main()     {           
  21. qDebug()<<"from thread slot_main:" <<currentThreadId();       
  22. } protected:     void run()     {           
  23. qDebug()<<"thread thread:"<<currentThreadId();           
  24. exec();       
  25. }   
  26. };   
  27. #include "main.moc" int main(int argc, char *argv[]) {       
  28.  QCoreApplication a(argc, argv);       
  29. qDebug()<<"main thread:"<<QThread::currentThreadId();      
  30.  Thread thread;       
  31. Dummy dummy;      
  32.  QObject::connect(&dummy, SIGNAL(sig()), &thread, SLOT(slot_main()));       
  33. thread.start();      
  34.  dummy.emitsig();       
  35. return a.exec(); } 

然后看到結(jié)果(具體值每次都變,但結(jié)論不變)

  1. main thread: 0x1a40 from thread slot_main: 0x1a40 thread thread: 0x1a48 

看到了吧,,槽函數(shù)的線程和主線程是一樣的,!

如果你看過Qt自帶的例子,你會發(fā)現(xiàn) QThread 中 slot 和 run 函數(shù)共同操作的對象,,都會用QMutex鎖住,。為什么?因為slot和run處于不同線程,需要線程間的同步,!

如果想讓槽函數(shù)slot在次線程運行(比如它執(zhí)行耗時的操作,,會讓主線程死掉),怎么解決呢,?

注意:發(fā)送dummy信號是在主線程, 接收者 thread 也在主線程中,。 參考我們前面的結(jié)論,,很容易想到: 將 thread 放到次線程中不就行了 這也是代碼中注釋掉的 moveToThread(this)所做的,去掉注釋,,你會發(fā)現(xiàn)slot在次線程中運行

  1. main thread: 0x13c0 thread thread: 0x1de0 from thread slot_main: 0x1de0 

這可以工作,,但這是 Bradley T. Hughes 強烈批判的用法。推薦的方法后面會給出,。

run中信號與QThread中槽

定義一個 Dummy 類,,在run中發(fā)射它的信號

也可以在run中發(fā)射 Thread 中的信號,而不是Dummy(效果完全一樣),,QThread 定義槽函數(shù),,重載run函數(shù)
 

  1. /*!  
  2. * \file main.cpp  
  3. *  
  4. * Copyright (C) 2010, dbzhang800  
  5. * All rights reserved.  
  6. *  
  7. */  
  8. #include <QtCore/QCoreApplication>   
  9. #include <QtCore/QObject>   
  10. #include <QtCore/QThread>   
  11. #include <QtCore/QDebug>    
  12. class Dummy:public QObject {       
  13. Q_OBJECT public:     Dummy(QObject* parent=0):QObject(parent){}   
  14. public slots: oid emitsig()       
  15. {  emit sig();    
  16. } signals:     void sig(); };    
  17. class Thread:public QThread {       
  18. Q_OBJECT public:      
  19. Thread(QObject* parent=0):QThread(parent) { //moveToThread(this); }   
  20. public slots:     void slot_thread()     {           
  21. qDebug()<<"from thread slot_thread:" <<currentThreadId();     }   
  22. signals:     void sig(); protected:     void run()     {           
  23. qDebug()<<"thread thread:"<<currentThreadId();          
  24.  Dummy dummy;           
  25. connect(&dummy, SIGNAL(sig()), this, SLOT(slot_thread()));          
  26.  dummy.emitsig();         e  
  27. xec();       
  28. }   
  29. };    
  30. #include "main.moc"  int main(int argc, char *argv[]) {       
  31. QCoreApplication a(argc, argv);       
  32. qDebug()<<"main thread:"<<QThread::currentThreadId();       
  33. Thread thread;       
  34. thread.start();       
  35. return a.exec(); } 

想看結(jié)果么?

  1. main thread: 0x15c0 thread thread: 0x1750 from thread slot_thread: 0x15c0 

其實沒懸念,,肯定是主線程

thread 對象本身在主線程,。所以它的槽也在要在主線程執(zhí)行,如何解決呢,?

(方法一)前面提了 moveToThread,這兒可以用,,而且可以解決問題。當(dāng)同樣,,是被批判的對象,。
 
(方法二)注意哦,這兒我們的信號時次線程發(fā)出的,,對比connect連接方式,,會發(fā)現(xiàn):

采用直接連接,槽函數(shù)將在次線程(信號發(fā)出的線程)執(zhí)行

這個方法不太好,,因為你需要處理slot和它的對象所在線程的同步,。需要 QMutex 一類的東西

推薦的方法,其實,,這個方法太簡單,,太好用了。定義一個普通的QObject派生類,,然后將其對象move到QThread中,。使用信號和槽時根本不用考慮多線程的存在。也不用使用QMutex來進行同步,Qt的事件循環(huán)會自己自動處理好這個,。

  1. /*!  
  2. * \file main.cpp  
  3. *  
  4. * Copyright (C) 2010, dbzhang800  
  5. * All rights reserved.  
  6. *  
  7. */  
  8. #include <QtCore/QCoreApplication>   
  9. #include <QtCore/QObject>   
  10. #include <QtCore/QThread>   
  11. #include <QtCore/QDebug>    
  12. class Dummy:public QObject {       
  13. Q_OBJECT   
  14. public:     Dummy(QObject* parent=0):QObject(parent)     {}   
  15. public slots:     void emitsig()     {         emit sig();       
  16. } signals:     void sig(); };    
  17. class Object:public QObject {       
  18. Q_OBJECT   
  19. public: Object(){} public slots:void slot() {    
  20. qDebug()<<"from thread slot:" <<QThread::currentThreadId();       
  21. }   
  22. };    
  23. #include "main.moc"  int main(int argc, char *argv[]) {      
  24.  QCoreApplication a(argc, argv);       
  25. qDebug()<<"main thread:"<<QThread::currentThreadId();      
  26.  QThread thread;       
  27. Object obj;       
  28. Dummy dummy;       
  29. obj.moveToThread(&thread);      
  30.  QObject::connect(&dummy, SIGNAL(sig()), &obj, SLOT(slot()));      
  31.  thread.start();       
  32. dummy.emitsig();       
  33. return a.exec(); } 

結(jié)果:恩,,slot確實不在主線程中運行(這么簡單不值得歡呼么?)

  1. main thread: 0x1a5c from thread slot: 0x186c 

小結(jié):QtQThread使用方法,,講到這里,。在本文中多次提到線程,那么對于QThread類,,它提供了與系統(tǒng)無關(guān)的線程,。QThread代表在程序中一個單獨的線程控制,在多任務(wù)操作系統(tǒng)中,,它和同一進程中的其它線程共享數(shù)據(jù),,但運行起來就像一個單獨的程序一樣。它不是在main()中開始,,QThread是在run()中開始運行的,。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多