【Qt高级】QThread与QTimer组合使用引出的信号槽执行在哪个线程的思考【2023.08.06】

源码见 testQThread_QTimer...

Qt 版本5.6.3

视频讲解:https://www.bilibili.com/video/BV15P411C79i/

链接: 视频讲解

简介

  想法很单纯,就是主线程启动一个子线程,子线程里启动一个定时器,定时执行一些任务,然鹅实际开发中警告不断。😒Qt

警告内容有:

1.QObject: Cannot create children for a parent that is in a different thread.

2.QObject::killTimer: Timers cannot be stopped from another thread

3.QObject::moveToThread: Cannot move objects with a parent

对线程和线程对象的理解

  线程对象是一个内核对象,就和常用的打开文件会获得一个文件句柄的句柄都属于稀缺的资源。线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含多个线程,每个线程可以并发执行不同的任务。

  一个进程一定有一个主线程 ,子线程是从主线程启动的。线程的关键特性除了并发性其实还有一个比较隐晦,就是线程的模块性。这是因为线程执行内容总应该是负责某块功能,具有一定独立性。举例来说,main.exe启动一个独立的线程来定时检查更新,显然这个线程负责的功能就很明确,如果更新检查除了问题,就检查这个线程涉及的所有代码。

  线程的退出:一般情况,线程干完活就自动释放了。还是拿上面的检查线程来说,如果他的使命是检查5次是否有更新,则检查完5次,没干的了,这个线程就会退了。除非是一直检查,这个线程才会一直运行下去。

关于QThread

  QThread这个类封装了对线程对象的管理,相当于我们雇佣了一个工人,需要发个工牌来知道都有哪些工人,通过工牌的工号发布指令。显然,如果只有一个主线程就不需要了,因为系统已经干了。

  具体到QThread的用法,主流的就2种。后续有代码解析。

方法一:继承QThread,并重写run方法、

方法二:将代码逻辑封装为一个类,

关于QTimer

  QTimer用于执行一些定时任务,往往采用信号槽的方式,连接timeout()函数至槽函数。

  QTimer的启动、停止、创建、销毁都需在同一个线程中。主线程中用的很easy,一旦涉及到子线程使用难度就上来了,需要保证QTimer的创建、启动、停止、销毁都是在同一线程。而往往我们都是在各种槽函数中对定时器停止。

Qt 槽函数到底执行在哪个线程?

  解决开篇警告的核心是搞清楚槽函数执行在哪个线程,以及为啥执行在那个线程。

这个答案来于互联网,然而我实测的结果不是这样的。

在多线程的Qt程序中,一个槽函数的执行线程是由发出信号的线程决定的,而不是连接该信号的线程。

具体来说:

  1. 如果信号是在主线程发出的,则槽函数会在主线程执行,即使该槽函数是在其他线程中连接的。
  2. 如果信号是在非GUI线程发出的,则槽函数会在该非GUI线程执行,即使是在主线程中连接的。
  3. 槽函数总是会在信号发出的线程中执行。

** 构造函数的执行顺序

  看似简单,我只要保证emit是在哪个线程即可。但实际开发中涉及类的组合关系,A类的成员类B类,在调用A类的构造之前会先调用B类的构造,B类的构造,而B类的构造还是在上一级的线程中。这也就导致了类A被moveToThread之后成了线程m_thred的资源,而A的B成员则还是主线程的资源。

c++ 复制代码
class CB{
public:
	CB(){}
private:
}
class CA{
public:
    CA(){ moveToThread(&m_thread); }
private:
	CB m_b; 
    QThread m_thread;
}

总结

  槽函数执行在哪个线程取决于发出信号的对象和槽函数的对象是在哪个线程构造的。要想保证成员类的槽函数都执行在子线程,成员类的构造就需在子线程,也就是成员类要以指针的方式组合,在合适的时机new对象出来。

相关推荐
Scott9999HH36 分钟前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社2 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海2 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖3 小时前
JDK 26 新特性详解
java·开发语言
马优晨3 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区5 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大6 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai6 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜6 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa6 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio