Qt线程实现分析-moveToThread vs 继承
2019-05-14 14:53
1051 查看
最近抽空研究了下QThread,使用起来方式多种多样,但是在使用的同时,我们也应该去了解Qt的线程它到底是怎么玩儿的。
Qt的帮助文档里讲述了2种QThread的使用方式,一种是moveToThread,另一种是继承QThread实现run方法,下面我们分别来分析下
一、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对象的槽函数中进行,因为只有槽函数是在工作线程中执行的,下面我记录了各个函数执行时所在的线程ID
由于线程ID是每次会发生编号,可能每个人测试的结果不一样
- Worker(): 0x4c34 主线程
- doWork(): 0x40c8 工作线程
- handleResults(): 0x4c34 主线程
- ~Worker(): 0x40c8 工作线程
细心的同学就会发现了,Worker对象的构造函数和析构函数不在同一个线程里边:Worker对象的事件循环已经放到子线程中了,Worker对象删除时,是工作线程通过抛出DeferredDelete事件执行的
下面结合我自己之前的一些使用理解,来分析下moveToThread是如何运作的:
假设有这么一种场景,需要把对象obj从线程A移动到线程B
首先我自己看了Qt的这个函数源码,这里把他翻译成为了白话文,我们大家可以来看下
1、一些异常判断
- 确认不在同一个线程里
- 移动的对象不能有父类
- 不能移动Widget窗体
- 支持移动一个无所属线程的对象到指定线程
- 对象不在C线程时,C线程不能把对象移动到B线程,只有A线程可以
2、moveToThread_helper
- 构造ThreadChange事件,发送给自己
- 迭代所有子对象,并执行moveToThread_helper方法
3、setThreadData_helper
- 循环遍历,把线程A中obj对象的所有事件移动到B线程中
- 如果移动了新事件到线程B中,则我们需要唤醒B线程,让他去派发事件
- 迭代所有子对象,并执行setThreadData_helper方法
二、继承QThread
假设说我们继承QThread实现了一个UsThread,使用起来可能像这样
UsThread thd;
经过我的实践,很可惜,除了run函数以外,所有的函数执行,包括对象都在主线程中
如果你想着thd.moveToThread这么干,那么可能会被打死
结论:个人推荐使用moveToThread这种方式进行子线程编写
更详细的测试结果可以参考
QThread使用——关于run和movetoThread的区别
相关文章推荐
- 理解QT线程中的moveToThread
- Qt多线程两种方式优劣,继承QThread还是MoveToThread
- Qt 线程 ---movetothread
- 在Qt使用moveToThread() qt的线程
- 源码分析继承Thread和实现Runnable来创建线程
- qt thread with movetothread
- 在Qt使用moveToThread()
- moveToThread的最简单用法(依葫芦画瓢即可)(使得线程也更偏向于信号槽的使用方法)
- 【Java基础_(线程篇_第一篇)】继承Thread;实现runnable;sleep、wait用法和区别;Thread和Runnable区别;线程停止
- 【Qt】QThread::moveToThread
- 线程使用方法之moveToThread
- 如果一个类通过继承Thread来实现多线程的话,则不适合多个线程共享资源,而通过实现Runnable就可以做到这一点
- 启动线程的五种方式方法(通过继承Thread类或实现Runnable接口)
- JAVA 线程的两种基本实现方法(继承Thread类和实现Runnable接口)
- Java传统多线程的实现有两种方法,继承Thread类或者实现Runnable即可.线程启动时调用start()方法.
- 线程实现Runnable接口比继承Thread的优势
- Linux线程的实现 & LinuxThread vs. NPTL & 用户级内核级线程 & 线程与信号处理
- Java 线程与进程的速度比较(继承Thread实现)
- 继承和实现两种创建线程的方式对比分析
- 线程创建的方法(清晰简单):1.继承Thread类 2.实现Runnable接口 3.实现Calable接口