一個QThread對象在程序控制中管理一個線程。線程在run()中開始執行。默認情況下,run()通過調用exec()啓動事件循環並在線程裏運行一個Qt的事件循環。
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
// ...
emit resultReady(result);
}
signals:
void resultReady(const QString &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::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
Worker槽中的代碼將在一個單獨的線程中執行,然而,可以將(來自任何對象、在任何線程中)任何信號與該槽自由地連接,在不同的線程裏連接信號和槽也是安全的,這要歸功於一個叫排隊的連接機制(queued connections)。
另一種使代碼運行在一個單獨的線程中的方法,是子類化QThread中並重新實現的run()。
例如:
class WorkerThread : public QThread
{
Q_OBJECT
void run() Q_DECL_OVERRIDE {
QString result;
emit resultReady(result);
}
signals:
void resultReady(const QString &s);
};
void MyObject::startWorkInAThread()
{
WorkerThread *workerThread = new WorkerThread(this);
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
上面的例子中,在run()返回後線程就會退出,在線程中將不會有任何的事件循環運行除非調用exec()。
注意一個線程實例位於實例化它的舊線程中,而非調用run()的新線程中,這意味着所有線程的排隊槽將在舊線程中執行。因此,開發人員希望在新線程調用槽必須使用worker-object方法,新槽不應直接在子類化QThread中來實現。
當子類化QThread時,請記住,構造函數在舊線程中執行,然而run()在新線程中執行。如果一個成員變量的訪問來自兩個函數,然後從兩個不同的線程訪問變量,需要檢查這樣做是否安全。
注:用在不同的線程中的對象進行交互時必須小心。詳見同步線程(Synchronizing Threads)。
管理線程
QThread會通知你觸發了一個信號當線程started()和finished()時,或者使用isFinished()和isRunning()來查詢線程的狀態。
可以通過調用exit()或quit()來停止線程。在極端情況下,你可能要強行terminate()一個執行線程。但是,這樣做是危險的。請閱讀文檔查看terminate()和setTerminationEnabled()的詳細信息。
從Qt4.8起,可以釋放運行剛剛結束的線程對象,通過連接finished()信號到QObject::deleteLater()。
使用wait()來阻塞調用的線程,直到其他線程執行完畢(或者直到指定的時間過去)。
QThread中還提供了靜態的、平臺獨立的休眠功能:sleep()、msleep()、usleep()允許秒,毫秒和微秒來區分,這些函數在Qt5.0中被設爲public。
注意:一般情況下,wait()和sleep()函數應該不需要,因爲Qt是一個事件驅動型框架。而不是wait(),關心監聽信號finished()。取代sleep(),可以考慮使用QTimer。
靜態函數currentThreadId()和currentThread()返回標識當前正在執行的線程。前者返回該線程的平臺特定的ID,後者返回一個線程指針。
要設置線程的名稱,可以在啓動線程之前調用setObjectName()。如果不調用setObjectName(),線程的名稱將是線程對象的運行時類型(上例中“WorkerThread”,因爲這是QThread子類的類名)。請注意,基於Windows的構建版本目前不可用。