【Qt基本功修炼】Qt线程的两种运行模式

1. 前言

QThread是Qt中的线程类,用于实现多线程运行。

QThread有两种工作模式,即

  • 消息循环模式
  • 无消息循环模式

两种模式分别适用于不同的场景。下面我们将从多个方面,讲解QThread两种工作模式的区别。

2. 消息循环模式

2.1 实现原理

QThread::run中的代码是在子线程中运行的。

QThread::run是虚函数,从它的默认实现的中可以看到,在QThread::run中启动了一个QEventLoop,即事件循环。部分源码如下所示(文件路径Qt5.9.9\5.9.9\Src\qtbase\src\corelib\thread\qthread.cpp):

QThread::run()
其中,

QThread::exec()

有了事件循环,子线程就可以像UI线程(即主线程)一样,进行消息处理。

2.2 使用方法

设worker是QObject子类的一个对象,具有信号和槽。如何让worker的槽函数运行于子线程中?可以使用 QObject::moveToThread()函数来将worker对象关联到某个子线程中。典型的写法如下:

QThread *thread = new QThread(this); // 线程对象
Worker *worker = new Worker(this); // 工人对象
worker->moveToThread(thread); // worker-thread 关联
thread->start(); // 启动线程

此后,通过Qt::AutoConnection/Qt::QueuedConnection/Qt::BlockQueuedConnection方式连接到worker的信号一旦被触发,Qt内部就会向worker所在子线程插入一条消息,等到消息循环处理到这条消息时,worker的槽函数会在子线程中被执行。

同理,若worker的某个信号通过Qt::AutoConnection/Qt::QueuedConnection/Qt::BlockQueuedConnection方式连接到主线程的一个对象的槽函数上,当此信号触发时,Qt也会向主线程的消息队列中插入一条消息。当主线程的消息循环处理到这条消息时,主线程对象的槽函数会在主线程中被执行。

简而言之,消息循环模式下,线程之间进行信号槽通信,通常都是由消息机制实现的,并且槽函数是在对象的关联线程中执行的。

2.3 线程退出方法

在消息循环模式下,通过调用QThread::quit() 或 QThread::exit() 方法,可以在对应线程的消息队列中插入一条退出消息,等到此条退出消息被处理时,QEventLoop::exec()返回,即消息循环退出。随后,QThread::run()函数也会退出,线程停止,线程资源被释放。相关Qt源码如下:

QThread::quit()

QThread::exit()

通过停止消息循环来停止线程,是一个异步操作。因为消息循环可能忙于执行某个函数,而无法处理退出消息,这就导致线程的退出时间不确定。所以,QThread::quit()通常和QThread::wait() 在主线程中搭配调用,以实现主线程等待子线程退出。等待时长可以由用户根据实际情况来设置。如果线程退出时间过长,则需要对耗时长的函数进行优化,以实现快速退出的效果。当然如果消息循环空闲,则退出消息会很快得到处理,消息循环和线程会很快退出。

3. 无消息循环模式

3.1 实现原理

用户继承 QThread并重载 QThread::run(),即可使默认的消息循环失效,用户将需要在子线程执行的代码全部写在重载的run()函数内。在这种模式下,只有重载的 run() 函数是在子线程中运行的。弄清楚这一点,才能准确判断一段代码的执行线程。

3.2 使用方法

示例代码如下:

class MyThread : public QThread
{
protected:virtual void run(){// process code here}
}

创建和启动线程:

 MyThread *thread = new MyThread(this);thread->start();

3.3 线程退出方法

因为没有消息循环,所以通过抛退出消息来使线程退出的QThread::quit()函数会失效。有两种退出/停止线程的方法:强制退出和正常退出。

3.3.1 强制退出

使用 QThread::terminate() 函数,可以让操作系统强制停止线程的执行。 调用 QThread::terminate() 后,线程不一定会立即退出,退出时间取决于操作系统。主线程可以调用 QThread::wait() 来等待线程退出。

正如 Qt 文档中所说,强制退出线程会导致资源来不及释放和清理,这会导致软件不稳定,非必要不使用。

3.3.2 正常退出

如果想要让线程正常退出,那么就需要在 QThread::run() 函数中插桩检测停止标记。一旦停止标记为真,则停止当前的工作,做好现场清理和资源释放,然后令 QThread::run() 函数返回即可。同时对外提供停止接口,用于设置停止标记。

示例代码如下:

class MyThread : public QThread
{
protected:virtual void run(){do{// 插桩检测停止标记if (m_stop_flag)break;// process code here// 插桩检测停止标记if (m_stop_flag)break;// process code here// 插桩检测停止标记if (m_stop_flag)break;// process code here} while (0);// 清理现场和资源clean();}// 对外提供停止接口void stop(){m_stop_flag = true;}private:bool m_stop_flag = false;
}

调用stop()接口以后,线程不会立即退出,需要调用 QThread::wait() 来等待线程退出。通过控制插桩位置和频率,可以控制线程退出的速度。停止代码如下:

thread->stop(); // 停止线程
thread->wait(2000); // 等待线程退出,不超过2s

4. 结语

在项目中,我们需要根据实际需求选择正确的线程运行模式,合理地实现软件功能,同时提高导致软件的稳定性和可靠性。

以上是Qt线程的基本使用方法,可以满足基本的使用需求。但用起来还是稍显麻烦。在此基础上,Qt Concurrent模块提供了启动线程的其他简便方式及高级用法,但万变不离其宗,打牢基础以后,学习高级用法会非常简单。对于Qt Concurrent模块,我们将在后面的文章进行讲解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/663448.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

virtualBox虚拟机安装ubuntu后的必要配置

1. 使能双向copy 粘贴功能。在device menu的 shared clipboard项, 选bidirectional. 2.启用共享文件夹。 在device 菜单的 shared folder 项配置, (对于日期乱码问题和命令行打不开的问题请见ubuntu18.04安装后时间日期乱码及terminal打不开解决方法_电脑日期变成…

ip地址是不是人在哪地址就在哪

在数字化世界中,IP地址作为一个关键的标识符,越来越多地被用于定位个人的地理位置。然而,这种定位是否准确?IP地址是不是人在哪地址就在哪?下面与虎观代理小二二一起来了解下吧。 IP地址通常表示的是数据包产生的地理…

PAT-Apat甲级题1004(python和c++实现)

PTA | 1004 Counting Leaves 1004 Counting Leaves 作者 CHEN, Yue 单位 浙江大学 A family hierarchy is usually presented by a pedigree tree. Your job is to count those family members who have no child. Input Specification: Each input file contains one te…

排序(5)——归并排序

六、归并排序 1.简介 归并排序也是一种很经典的排序算法,采用分治的思想方法进行数据的处理。归并讲究的是先拆后合,也就是分治中的分而治之。在拿到一组数据后,程序会将整个数据进行不断拆分直至有序,因为单个元素必然有序&…

2024美赛数学建模C题思路+模型+代码+论文

2024美赛A-F题思路代码模型论文:2.2开赛第一时间更新,获取见文末名片 美赛流程以及经验分享 今天主要和大家分享一下我之前参加美赛的经验,主要分两部分来讲。一部分是美赛流程,另一部分是美赛经验。 一 美赛流程 比赛前&#x…

教你怎么给接口定义错误码

错误码一般包括三个要素: 前缀标识:区分错误类型,比如请求不合法,还是服务器处理错误。模块标识:区分到底是哪个模块的错误。错误代码:区分具体是什么问题。 从错误码的符号组成上看又分为三类&#xff1…

网络发展历程及SD-WAN的优势

自网络出现以来,经历了不同时期的发展阶段,而SD-WAN作为网络发展的新趋势,以其独特的优势满足了当今企业对于高效、灵活和成本控制的网络需求。 一、网络发展历程 (1)初始阶段:专线网络 从1980年代到2000…

VBA数据库解决方案第八讲:SQL语句及打开记录集

《VBA数据库解决方案》教程(版权10090845)是我推出的第二套教程,目前已经是第二版修订了。这套教程定位于中级,是学完字典后的另一个专题讲解。数据库是数据处理的利器,教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…

20240202金融读报1分钟小得

1、今年份KPI?沿江沿河省级分行要继续坚持开展“长江行”“黄河行”活动,深入研究不同区域、不同河段的特点和需求,研究制定差异化、多元化金融服务方案。 2、作为长线投资者,联博对中国股市非常乐观。当前A股市场是全球最具吸引力…

Ubuntu 编译安装 nginx

Ubuntu 22.04.1 LTS 编译安装 nginx-1.22.1 安装依赖 sudo apt install libgd-dev 下载nginx wget http://nginx.org/download/nginx-1.22.1.tar.gz 解压nginx tar -zvxf nginx-1.22.1.tar.gz 编译安装 cd nginx-1.22.1 编译并指定安装位置,执行安装之后会创建指…

flowable 设置自定义属性教程

概述 由于工作需要给flowable工作流设计器添加自定义属性,以满足功能实现。所以这篇文章介绍下用flowable 开源的的flowable-ui 前端添加自定义属性,后端解析属性值的例子。 技术栈 序号技术点名称版本1Flowable6.8.0 使用的是flowable6.8.0 版的代码…

画质和场景双需求下,海信电视U8KL的变与不变

又到一年春节,最近几年大家过年的方式越来越丰富,但是跟家人在一起看春晚依然是主流,电视也是过年不可或缺的家庭成员。 当然,随着大家对生活品质的要求更高,对电视的要求也变得更高了。比如,现在春晚直播…

Java实现对接微信支付功能接口详解(二)

本系列文章简介: 微信支付是一种在线支付解决方案,允许用户通过微信内的支付功能进行付款。它提供了多种支付方式,包括扫码支付、公众号支付、小程序支付等。在Java应用程序中实现微信支付功能,可以为用户提供方便快捷的支付体验。…

爬虫笔记(三):实战qq登录

咳咳,再这样下去会进橘子叭hhhhhh 以及,这个我觉得大概率是成功的,因为测试了太多次,登录并且验证之后,qq提醒我要我修改密码才可以登录捏QAQ 1. selenium 有关selenium具体是啥,这里就不再赘述了&#x…

leetcode c++ 超出内存限制

给两个主要原因,这两个原因,如果在递归或者循环里就很容易导致内存超出限制 首先就是误用 如果只是变量的变化实现的话,或者-就可以了,不需要写成AAx的形式,那样会重新开辟一块内存 其次就是值传递 值传递也是会开辟…

在Linux中对Nginx进行安全加固

准备工作 在IP为x.x.x.x的服务器上安装nginx,确保Linux系统为nginx环境。 检查nginx是否配置nginx账号锁定策略 配置nginx账号锁定策略,降低被攻击概率。 第一步,查看nginx的锁定状态。 命令:passwd -S nginx 若结果出现“P…

【gcc】webrtc发送侧计算 丢包率

大神的分析 : 提到: 每当收到cc-feedback或者收到RR-report的时候就能统计出丢包率,在cc-controller中就会调用SendSideBandwidthEstimation::UpdatePacketsLost()去更新丢包率,同时进行码率预估 G:\CDN\rtcCli\m98\src\modules\congestion_controller\goog_cc\send_side_b…

今日arXiv最热NLP大模型论文:像人一样浏览网页执行任务,腾讯AI lab发布多模态端到端Agent

Agent的发展成为了LLM发展的一个热点。只需通过简单指令,Agent帮你完成从输入内容、浏览网页、选择事项、点击、返回等一系列需要执行多步,才能完成的与网页交互的复杂任务。 比如给定任务:“搜索Apple商店,了解iPad智能保护壳Sm…

数据结构与算法--面试问答

问题与简答 数据结构与算法篇 1. 概述 解决问题的效率 解决问题方法的效率,跟数据的组织方式有关,跟空间的利用效率有关,也跟算法的巧妙程度有关 抽象数据类型 抽象数据类型(Abstract Data Type,ADT)是一种对"数据类型…

Qt中的绝对位置与相对位置

在Qt的开发中,有时候需要获取鼠标点击的位置的坐标。在Qt中坐标分为相对坐标和绝对坐标;相对坐标是以控件的左上角为(0,0)点的坐标系的坐标,绝对坐标是以显示器屏幕的左上角为(0,0&a…