程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> QThread進程可能出現的問題

QThread進程可能出現的問題

編輯:關於C語言

   首先還是先說下故事的背景,當我們點擊一個按鈕或者類似控件之類的東西,我們可能希望它完成很復雜的操作,但是我們又不希望程序卡在那裡等待這個復雜操作的執行結束,這裡就需要用到多線程,雖然我到現在也不太清楚QT中到底怎樣使用多線程是合理的,但是還是總結一下,方便以後查閱。

   通常我們會在很多網站上獲得這樣的實現多線程的據說是不錯的方法!也給一個相關的鏈接:

http://llydmissile.blog.51cto.com/7784666/1280183,這裡已經對一些多線程的方法進行總結了,這裡也不贅述了,直接貼出核心代碼進行分析。

QThread pingThread;
QObject::connect(&obj, SIGNAL(sig()), this, SLOT(getData()), Qt::QueuedConnection);
Dummy dummy;
obj.moveToThread(&pingThread);
QObject::connect(&dummy, SIGNAL(sig()), &obj, SLOT(pingIp()), Qt::QueuedConnection);
pingThread.start();
dummy.emitsig();

這裡的除了第二行的代碼都是原來大家抄來抄去的代碼,這裡要說明的是這段程序不在main中,因此沒有消息循環一說,而且這裡的obj是當前類的成員,至於為什麼要是成員而不是局部變量將在後文提到,這裡的pingThread是子線程,我們把obj移到這個線程中,也就相當於obj所在的類就是子線程了。這裡第六行的槽pingIp是我們自己定義的,具體的實現這裡不上代碼了,總之是一系列很耗時的操作。並且操作結束後我們需要對操作的結果進行返回,這可如何是好啊,SLOT沒返回值啊,有返回值也帶不回來啊,這有用這個obj的成員,在SLOT中將結果存在obj的成員變量中,一定要是全局的,要不不能在外面取出來了。

下面我們說這個關鍵的第二行,這裡建立了一個連接,信號的發出者是obj,接受者是當前類,所以這裡就要在obj類的pingIp槽結束的時候發出一個信號sig,這裡為了說明情況給出obj類的頭文件

#include <QObject>
class Object: public QObject
{
    Q_OBJECT
public:
    Object();
    std::vector<QString> m_linkVec;
    std::vector<int> m_succeedVec;
    std::vector<QString> m_ipVec;
signals:
    void sig();
public slots:
    void pingIp();
private:
                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                   
};

這裡定義的幾個vector都是最後處理後要帶回來的結果,sig()就是obj要發出的信號了,這個信號要在pingIp結束前的最後一行發出,然後這個信號就會被連接到我們之前在第二行建立的槽,通過getData()這個槽將所需要的結果取回到主線程。


這裡會存在一個問題,就是當子線程還在執行的時候可能主線程已經結束了,這個是完全不可以的,所以這裡就需要考慮對象的生存期的問題,由於子線程還在執行而主線程已經結束,那麼勢必會對主線程中定義的臨時變量,比如這個第一行的pingThread,這個釋放直接會導致程序的崩潰,因為線程的對象都沒了,還怎麼執行線程啊,程序肯定跑飛了,所以在子進程結束前這個pingThread是不能析構或者釋放的,網上那些人的代碼之所以沒有問題是因為他們都是在主函數進行測試的,主函數當然是你關閉了才會結束,要不就會一直消息循環,所以程序不會跑飛,i我們的不一樣,我們是在類的成員函數中進行的,執行完是很正常的,所以就是執行完了也要對這個pingThread保留,防止由於子進程沒結束造成程序錯誤,因此要把這個pingThread設置成類的成員,obj設置成成員是因為要取回數據,這兩個的目的是不一樣的。


   最後總結一下,由於是用信號槽機制實現的,但是連接的是不同線程之間的信號和槽,因此,我們平時不常用到的信號槽的第五個參數“消息傳遞方式”就需要設置了,這裡對這個參數進行一下簡單的說明。

Qt::AutoConnection
Qt::DirectConnection
Qt::QueuedConnection
Qt::BlockingQueuedConnection
Qt::UniqueConnection
Qt::AutoCompatConnection

這裡面一共有六種方式,前兩種比較相似,都是同一線程之間連接的方式,不同的是Qt::AutoConnection是系統默認的連接方式,這種方式連接的時候,槽不是馬上被執行的,而是進入一個消息隊列,待到何時執行就不是程序員可以知道的了,第二種是直接連接,也就是只要信號發出直接就到槽去執行,屬於比較無腦的方式。第三種和第四種是相似的,都是可以在不同進程之間進行連接的,不同的是,這裡第三種是在對象的當前線程中執行,並且是按照隊列順序執行。當當前線程停止,就會等待下一次啟動線程時再按隊列順序執行  ,等待QApplication::exec()或者線程的QThread::exec()才執行相應的槽,第四種是必須信號和曹在不同線程中,否則直接產生死鎖)這個是完全同步隊列只有槽線程執行完才會返回,否則發送線程也會等待,相當於是不同的線程可以同步起來執行,第五種跟默認工作方式相同,只是不能重復連接相同的信號和槽,第六種是為了連接QT4 到QT3的信號槽機制兼容方式,工作方式跟Qt::AutoConnection一樣。顯然這裡我們應該選擇第三種方式,我們不希望子線程沒結束主線程還要等,我們只是希望利用這個空閒時間去干別的事情,當子線程執行完了,只要發消息給主線程就行了,到時候主線程會去響應。

本文出自 “賣萌程序員” 博客,請務必保留此出處http://7677869.blog.51cto.com/7667869/1288018

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved