2013-10-30 83 views
1

這個例子用於測試QThread。主要目標是能夠在專用線程中運行耗時的阻塞方法,並且可以在任何時候終止並重新啓動線程。阻塞方法是第三方庫,這是我們無法控制的。我知道Qt阻止使用QThread :: terminate的文檔,但目前我沒有看到任何其他方式。QThread終止和親和力

下面是在專用線程中運行所需代碼的一個示例。基本上有一種方法可能需要10-15分鐘來處理。沒有合適的地方添加moveToThread,以便將親和力帶回到QThread :: termination的主線程,或者執行processEvent來處理QThread :: quit()方法。

void run() 
{ 
    // initiate variables 
    thirdparty lib(var1, var2); 
    int res = lib.execute(var3, var4, var6); 
    // handle result and exit 
} 

在Windows 7

運行代碼使用Qt 4.7產生這個輸出

Test::doWork thread: QThread(0x219e960) 
Test::started thread: QThread(0x239bce8) 
Test::doTerminate thread: QThread(0x239bce8) 
Test::doWork thread: QThread(0x239bce8) 
QObject::moveToThread: Current thread (0x219e960) is not the object's thread (0x239bce8). Cannot move to target thread (0x239bd20) 

的moveToThread API在試驗的第二執行失敗::的doWork()方法。這似乎是因爲Test實例與另一個線程(此時終止)有親和力。我怎樣才能改變親和力?

終止並重新啓動QThread的推薦方式是什麼?我是否需要刪除測試實例?

該代碼;

#include <QCoreApplication> 
#include <QThread> 
#include <iostream> 
#include <QDebug> 
#include "Worker.h" 
#include "Windows.h" 

class Test : public QObject 
{ 
    Q_OBJECT 
    QThread* m_thread; 
    int  m_state; 

public: 
    Test() : m_thread(0), m_state(3) { } 

public slots: 
    void doWork() 
    { 
     qDebug() << "Test::doWork thread:" << QObject::thread(); 
     if (!m_thread) 
     { 
     m_thread = new QThread(); 
     QObject::moveToThread(m_thread); 
     QObject::connect(m_thread, SIGNAL(started()), this, SLOT(started())); 
     QObject::connect(m_thread, SIGNAL(finished()), this, SLOT(finished())); 
     QObject::connect(m_thread, SIGNAL(terminated()), this, SLOT(terminated())); 
     m_thread->start(); 
     } 
    } 

    void started() 
    {  
     qDebug() << "Test::started thread:" << QObject::thread(); 
     Sleep(60); 
    } 

    void finished() 
    { 
     qDebug() << "Test::finished thread:" << QObject::thread(); 
    } 

    void terminated() 
    { 
     qDebug() << "Test::terminated thread:" << QObject::thread(); 
    } 

    void doTerminate() 
    { 
     qDebug() << "Test::doTerminate thread:" << QObject::thread(); 
     QObject::disconnect(m_thread); 
     m_thread->terminate(); 
     m_thread->wait(); 
     m_thread = NULL; 
    } 

    int state() 
    { 
     return m_state; 
    } 
}; 

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

    test.doWork(); 
    Sleep(10); 

    test.doTerminate(); 
    Sleep(10); 

    test.doWork(); 
    return a.exec(); 
} 
+0

在殺死m_thread之前,你可以將'Test'對象返回主線程,但這似乎有點奇怪。如果你不得不重新開始,爲什麼要殺死線程? – thuga

+0

你也應該考慮把'm_thread' ['finished()'](http://qt-project.org/doc/qt-5.0/qtcore/qthread.html#finished)信號連接到它的['deleteLater ()'](http://qt-project.org/doc/qt-5.0/qtcore/qobject.html#deleteLater)插槽。現在你將'm_thread'值設置爲'0',但是我沒有看到你在任何地方摧毀了這個對象。 – thuga

+0

第三方方法使用許多參數執行。如果參數不正確,您可能想要終止執行,然後用不同的參數重新啓動。 – Lars

回答

0

除了使用terminate之外,還可以調用更多可接受的函數quit()。

+0

QThread :: quit文檔狀態「告訴線程的事件循環退出並返回代碼0(成功)」。這會中斷當前事件還是等待它完成然後退出? – Lars

+0

我期望它完成它在事件循環中處理的任何事件,然後乾淨地退出。 – TheDarkKnight

+0

感謝您的回覆。這種方法的問題在於,正在處理的事件是一項耗時的任務,它將捆綁系統資源併產生不再需要的數據。所以我選擇了一種更有力的方法。 – Lars