2011-09-15 82 views
3

我想在單獨的線程中執行一些工作,並在工作完成時停止該線程。QThread不會停止/不處理信號

我已經建立了這樣

thread.connect(workerClass, SIGNAL(finished()), SLOT(quit())); 

但連接的退出()當我發射完成的()信號時隙不會被調用。命令行不顯示與連接失敗相關的任何警告。

我創建了一個簡單的測試項目,以縮小問題,我也得到相同的行爲:

TestClass.h:

#ifndef TESTCLASS_H 
#define TESTCLASS_H 
class TestClass : public QObject 
{ 
    Q_OBJECT 
public: 
    TestClass() { } 
signals: 
    void finished(); 
public slots: 
    void doWork(); 
} 
#endif // TESTCLASS_H 

TestClass.cpp:

#include "TestClass.h" 
#include <QtCore/QDebug> 
void TestClass::doWork() 
{ 
    qDebug() << "Starting"; 
    for(long i = 0; i < 1000000000; i++); 
    qDebug() << "Done"; 
    emit finished(); 
}; 

和main.cpp:

#include <QtCore/QCoreApplication> 
#include <QtCore/QThread> 
#include "TestClass.h" 

int main(int argc, char* argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    TestClass testClass; 
    QThread testThread; 

    testClass.moveToThread(&testThread); 

    testThread.connect(&testClass, SIGNAL(finished()), SLOT(quit())); 
    testClass.connect(&testThread, SIGNAL(started()), SLOT(doWork())); 

    testThread.start(); 
    testThread.wait(); 

    return 0; 
} 

所以這是我期望發生:

  1. 一旦testThread.start()得到處理,線程的run()函數被調用,它在內部調用exec(),並開始一個事件循環。另外它會拋出一個started()信號。
  2. testClass已將其doWork()插槽調用。
  3. TestClass::doWork()完成時,它會拋出一個finished()信號。
  4. testThread事件循環從等待作爲該線程已結束接收該信號並且將其轉發給其quit()
  5. testThread.wait()回報。

步驟1-3工作,我得到qDebug()輸出。 問題在於步驟4:信號被觸發並轉發到某個事件循環(我調試了一下,但無法弄清楚它被觸發了哪個事件循環),但從不調用quit()插槽。

我在做什麼錯?

P.S .:請不要建議子類化QThread來代替,我嘗試這種方法的全部觀點是因爲我想避免子類化QThread。

回答

4

我認爲問題在於你實際上沒有在場景中運行Qt事件循環。如果你用a.exec()(它啓動Qt事件循環)代替testThread.wait(),你應該看到你的信號/插槽得到正確處理。

如果您希望應用程序在線程完成時退出,則可以使用QCoreApplication的quit()插槽來完成此操作。

+1

是的,我認爲你是對的。他應該'int ret = a.exec(); testThread.wait();返回ret;'。 – RedX

+0

默認情況下線程有自己的事件循環,所以我認爲這就足夠了。事實證明,如果主事件循環沒有運行,它們不值一提。你們是對的。 –

+0

如果您在其中調用int QThread :: exec(),QThread只會有一個事件循環運行。事件循環基本上是一個處理while循環中的東西的隊列。沒有處理事件和信號的循環=>沒有信號到達。 –

1

我有同樣的問題,並找到答案。這是我的問題: What is the use of QThread.wait() function?

要解決您的問題,您不需要運行a。exec(),你需要做的是,而不是調用嘗試嚮應用程序的事件循環發送信號的quit()(它顯然不存在),你必須直接調用它。

因此,對於你的代碼,刪除線:

testThread.connect(&testClass, SIGNAL(finished()), SLOT(quit())); 

,而不是和:

emit finished(); 

用途:

this->thread()->quit(); 

田田......問題就迎刃而解了。獲得的經驗:不要試圖通過qt signal-slot機制退出工作線程,因爲你的信號並不會到達它們所期望的位置(工作線程的事件循環),但它們最終會在創建線程代替。你永遠不知道那個線程正在做什麼,如果它的事件循環正在運行或者沒有運行,並且這對你的工作線程來說不應該是事務性的,反而直接調用quit。