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的区别

相关文章
相关标签/搜索