Qt線程實現分析-moveToThread vs 繼承

最近抽空研究了下QThread,使用起來方式多種多樣,可是在使用的同時,咱們也應該去了解Qt的線程它究竟是怎麼玩兒的。多線程

Qt的幫助文檔裏講述了2種QThread的使用方式,一種是moveToThread,另外一種是繼承QThread實現run方法,下面咱們分別來分析下函數

1、moveToThread

首先咱們來先分析move這種方式,他的使用可能像下面這樣測試

class Worker : public QObject
{
public slots:
    void doWork(const QString &) {
        emit resultReady(result);
    }
};

class Controller : public QObject
{
    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();
    }
};

這是一個標準的多線程使用方式,複雜的邏輯操做咱們能夠放在Worker對象的槽函數中進行,由於只有槽函數是在工做線程中執行的,下面我記錄了各個函數執行時所在的線程IDui

因爲線程ID是每次會發生編號,可能每一個人測試的結果不同this

  • Worker(): 0x4c34 主線程
  • doWork(): 0x40c8 工做線程
  • handleResults(): 0x4c34 主線程
  • ~Worker(): 0x40c8 工做線程

細心的同窗就會發現了,Worker對象的構造函數和析構函數不在同一個線程裏邊:Worker對象的事件循環已經放到子線程中了,Worker對象刪除時,是工做線程經過拋出DeferredDelete事件執行的.net

下面結合我本身以前的一些使用理解,來分析下moveToThread是如何運做的:線程

假設有這麼一種場景,須要把對象obj從線程A移動到線程B翻譯

首先我本身看了Qt的這個函數源碼,這裏把他翻譯成爲了白話文,咱們你們能夠來看下code

一、一些異常判斷

  1. 確認不在同一個線程裏
  2. 移動的對象不能有父類
  3. 不能移動Widget窗體
  4. 支持移動一個無所屬線程的對象到指定線程
  5. 對象不在C線程時,C線程不能把對象移動到B線程,只有A線程能夠

二、moveToThread_helper

  1. 構造ThreadChange事件,發送給本身
  2. 迭代全部子對象,並執行moveToThread_helper方法

三、setThreadData_helper

  1. 循環遍歷,把線程A中obj對象的全部事件移動到B線程中
  2. 若是移動了新事件到線程B中,則咱們須要喚醒B線程,讓他去派發事件
  3. 迭代全部子對象,並執行setThreadData_helper方法

2、繼承QThread

假設說咱們繼承QThread實現了一個UsThread,使用起來可能像這樣對象

UsThread thd;

通過個人實踐,很惋惜,除了run函數之外,全部的函數執行,包括對象都在主線程中

若是你想着thd.moveToThread這麼幹,那麼可能會被打死

結論:我的推薦使用moveToThread這種方式進行子線程編寫

更詳細的測試結果能夠參考
QThread使用——關於run和movetoThread的區別

相關文章
相關標籤/搜索