2017-03-16 126 views
0

我希望使用QThread構建我的Qt應用程序,因爲我想將長進程窗體MainWindow分隔爲線程。Qt線程兩個參數

我在此代碼已經一個問題:

class Worker : public QObject 
{ 
    Q_OBJECT 

public slots: 
    void doWork(const std::string &param2, std::string &param2) { 
     int result; 
     /* ... here is the expensive or blocking operation ... */ 
     emit resultReady(result); 
    } 

signals: 
    void resultReady(const int &result); 
}; 

class Controller : public QObject 
{ 
    Q_OBJECT 
    QThread workerThread; 
public: 
    Controller() { 
     Worker *worker = new Worker; 
     worker->moveToThread(&workerThread); 
     connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); 
     connect(this, &Controller::input,&Controller::output, worker, &Worker::doWork); 
     connect(worker, &Worker::resultReady, this, &Controller::handleResults); 
     workerThread.start(); 
    } 
    ~Controller() { 
     workerThread.quit(); 
     workerThread.wait(); 
    } 
public slots: 
    void handleResults(const int &); 
private: 
    string input; 
    string output; 
}; 

我希望我的代碼可以將兩個值(輸入,輸出)字符串的QThread和作爲結果發出的信號爲int值。但是,列出的代碼不起作用。我在.Net中尋找解決方案看起來像blackgroundWorker,並且具有類似的功能。

我應該這樣做嗎?

編輯

我不能編譯這一點。我得到了錯誤:

Severity Code Description Project File Line Suppression State 
Error C2664 'QMetaObject::Connection QObject::connect(const QObject *,const char *,const char *,Qt::ConnectionType) const': cannot convert argument 2 from 'std::string Controller::* ' to 'const char *' GPCTool C:\repo\Tool\Controller.cpp 21 
+0

究竟你「不上班」的意思是什麼不編譯?它會崩潰嗎?它會產生意外的結果嗎? – SingerOfTheFall

+0

我收到了錯誤代碼,我在編輯 – Lisek

+0

中寫到了,好像你的第二個'connect'參數太多了,不是嗎? – SingerOfTheFall

回答

0

首先,這行代碼將無法正常工作:

connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); 

workerThread生活在你的主線程,而worker生活在由(創造)workerThread處理的線程。因此,當QThread::finished被觸發時,QObject::deleteLater將被異步調用(請參閱Qt::AutoConnection),但是線程已經完成,異步調用將永遠不會完成。

它甚至變得更糟。即使調用QObject::deleteLater,延期刪除也不會發生,原因相同:線程已完成。


connect(this, &Controller::input, &Controller::output, worker, &Worker::doWork); 

該調用不匹配的connect()任何原型。您無法將變量連接到插槽。

無論是創建一箇中間信號:

class Controller : public QObject 
{ 
    Q_OBJECT 
    QThread workerThread; 
public: 
    Controller() { 
     Worker *worker = new Worker; 
     worker->moveToThread(&workerThread); 
     connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); 
     connect(this, &Controller::callDoWork, worker, &Worker::doWork); 
     connect(worker, &Worker::resultReady, this, &Controller::handleResults); 
     workerThread.start(); 
     emit callDoWork(input, output); 
    } 
    ~Controller() { 
     workerThread.quit(); 
     workerThread.wait(); 
    } 
signals: 
    emit callDoWork(std::string, str::string); 
public slots: 
    void handleResults(const int &); 
private: 
    string input; 
    string output; 
}; 

或使用QMetaObject::invokeMethod()

Controller() { 
    Worker *worker = new Worker; 
    worker->moveToThread(&workerThread); 
    connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); 

    connect(worker, &Worker::resultReady, this, &Controller::handleResults); 
    workerThread.start(); 
    QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection, Q_ARG(std::string, input), Q_ARG(std::string, output)); 
} 

注意,對於這兩個解決方案工作,你需要用Q_DECLARE_METATYPE和qRegisterMetaType(見http://doc.qt.io/qt-5/qmetatype.html#Q_DECLARE_METATYPE)註冊std::string

而且你還希望通過std::string *output更換std:string &output,爲的Qt將會使兩個線程之間output副本,你不會看到的變化反映到原來output變量。


connect(worker, &Worker::resultReady, this, &Controller::handleResults); 

這並不編譯,因爲resultReady的簽名不匹配handleResults。要將信號連接到插槽,它們必須採用相同的參數。

我建議你閱讀Qt Signal & Slots documentation


關於你使用線程,我想你應該看看QThreadPoolQRunnable

+0

connect(this,&Controller :: input,&Controller :: output,worker,&Worker :: doWork);在這一行我想傳輸輸出和輸入字符串作爲參數做工作方法 – Lisek

+0

我已經更新了我的答案。您應該花時間閱讀Qt信號和插槽文檔。 –

+0

謝謝你的回答。我使用第一種方式,我會閱讀更多鄰接插槽和信號:)。 – Lisek

0

您可能會閱讀這個愚蠢的博客,聲稱必須創建一個工作對象並將其用於純線程,而不是簡單地從QThread派生並實現run()

由於您的工作負載只是一次只需要一個功能,因此更簡單。

在這兩種情況下,僅僅通過構造函數或setter方法值傳遞給類,實在沒有必要將它們作爲參數傳遞給doWork()

+2

這不是一個「愚蠢的博客聲稱」,這是'QThread'的意圖是由Qt開發人員使用的方式。你可以用兩種方法做,但聲稱這種或那種方式是「完全錯誤的」......是完全錯誤的。 – SingerOfTheFall

+0

因爲它聲稱是使用'QThread'的方式,所以它很愚蠢,因爲沒有一種方法。 使用'moveToThread'工作人員是一個很好的選擇,當工作人員正在做基於事件循環的工作。如果工作者正在運行單個函數或無限循環,那麼這只是不必要的編碼開銷,除了必須處理兩個對象而非一個對象的複雜性之外。 –