【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对象出来。

相关推荐
小羊没烦恼!4 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
伞伞悦读4 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
C语言小火车4 天前
C/C++ 为什么需要编译器?
开发语言·c++
霍霍的袁4 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
孙启超4 天前
【AI开发之Rust】第 11 课:智能指针与内部可变性
开发语言·后端·rust
此生决int4 天前
深入理解C++系列(20)——C++11(下)
开发语言·c++
慧都小项4 天前
当边缘AI上产线:QtitanDocking 如何让工业 HMI 实现多视图协同
人工智能·qt·ui·边缘计算·qt6.3
CoderYanger4 天前
A.每日一题:835. 图像重叠
java·开发语言·程序人生·leetcode·面试·职场和发展·学习方法
伞伞悦读4 天前
【第37期】Python JSON 与配置详解:序列化、反序列化、嵌套结构和配置文件
开发语言·python·json
CCCCCCCCharlie4 天前
Linux进程控制四大核心操作
linux·开发语言