Qt中QThread的用法

1. QThread使用簡介

The QThread class provides a platform-independent way to manage threads.html

QThread提供了一個平臺獨立的方式去管理線程操做安全

A QThread object manages one thread of control within the program. QThreads begin executing in run(). By default, run() starts the event loop by calling exec() and runs a Qt event loop inside the thread.app

一個QThread實例對象在程序中管理着線程的控制邏輯。QThreads在run()中開始執行屬於本身線程的邏輯。默認,QThread在run()方法內調用exec()開啓了一個屬於本身線程內部的事件循環。less

You can use worker objects by moving them to the thread using QObject::moveToThread.ide

你能夠寫一個繼承自QObjet的worker對象來實現你的業務邏輯,而後利用 QObject::moveToThread()方法將worker實例對象移動到你指望它被執行的線程對象中去, 實現線程關聯,下面稱這種方式爲work-object模式函數

class Worker : public QObject{
    Q_OBJECTpublic slots:
    void doWork(const QString &parameter) {
        QString result;
        /* ... here is the expensive or blocking operation ... */
        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 &);};

The code inside the Worker's slot would then execute in a separate thread. However, you are free to connect the Worker's slots to any signal, from any object, in any thread. It is safe to connect signals and slots across different threads, thanks to a mechanism called queued connections.oop

the Worker's slot doWork()邏輯將在一個獨立的線程中去執行;這樣你就能夠自由的鏈接在 任何線程內 任意對象 的信號到 the Worker's slots;得益於Qt信號與槽的queued connections機制,跨線程鏈接信號和槽是安全的ui

Another way to make code run in a separate thread, is to subclass QThread and reimplement run(). For example:this

另一種讓代碼運行在一個獨立線程內的方法就是,繼承QThread,重寫run()方法,例子以下:spa

class WorkerThread : public QThread{
    Q_OBJECT
    void run() Q_DECL_OVERRIDE {
        QString result;
        /* ... here is the expensive or blocking operation ... */
        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();}

In that example, the thread will exit after the run function has returned. There will not be any event loop running in the thread unless you call exec().

在上面的例子中,線程將在run()方法執行返回後退出,這個線程內沒有事件循環,除非你在run()函數內部最後調用exec()開啓一個事件循環。

It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.

記住,一個線程實例對象存活在建立它的老線程內,不是run()啓動後的新線程內,可是在run()裏構建的對象是屬於子線程的。 這就意味着全部線程的槽函數都將在老線程中執行;所以,開發者若是但願槽函數在新線程中執行,就必須使用work-object方式;注意:槽函數定義不 應該在繼承QThread的子類中實現。

When subclassing QThread, keep in mind that the constructor executes in the old thread while run() executes in the new thread. If a member variable is accessed from both functions, then the variable is accessed from two different threads. Check that it is safe to do so.

當繼承QThread時,記住這個線程構建是在老的線程中,而run()執行在新的線程中。若是一個變量在兩個線程中訪問都被使用,須要確保這樣操做是否安全。

2. 總結:

  • QThread使用,請使用work-object這種模式,邏輯操做在worker中實現,利用movetoThread與新的線程實現線程關聯,調用start方法開啓新的線程便可.

  • 若是非要使用繼承QThread重寫run方法來實現你的邏輯,請認真瞭解QThread的實現機制和注意事項,遵循以下原則:

    When to subclass and when not to?

    何時使用繼承QThread,何時不使用? + 若是你不須要事件循環,你應當採用繼承; + 若是你須要事件循環,並但願在新線程內處理信號與槽,你不須要繼承。

    • If you do not really need an event loop in the thread, you should subclass.

    • If you need an event loop and handle signals and slots within the thread, you may not need to subclass.

  • 使用QThread的注意事項:



    1. 繼承QThread,並在繼承類中定義槽方法,而後使用movetoThread(this)/movetoThread(self)是一種糟糕的實踐

    1. 明確你的槽是在主線程仍是子線程中執行

若是你想了解更多,請參考下面這些文章,並認真研讀qt官方文檔,Qt的官方文檔永遠是解決你問題的最好幫手

參考:

相關文章
相關標籤/搜索