Qt之線程(QThread)

   QThread類提供了一個平臺無關的方式來管理線程。 
    一個QThread對象在程序控制中管理一個線程。線程在run()中開始執行。默認情況下,run()通過調用exec()啓動事件循環並在線程裏運行一個Qt的事件循環。 
    可以使用worker-object通過QObject::moveToThread將它們移動到線程。
class Worker : public QObject
{
    Q_OBJECT

public slots:
    void doWork(const QString &parameter) {
        // ...
        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的構建版本目前不可用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章