Qt线程基础,多线程使用注意点,目前支持的线程种类。

news2024/11/28 22:55:59

Qt线程基础

  • 一、什么是线程?
  • 二、GUI线程和工作线程
  • 三、同时访问数据
  • 四、使用线程
    • 1、何时使用线程的替代品
    • 2、应该用哪种Qt线程技术?
  • 六、Qt中的多线程技术
    • 1、QThread:带有可选事件循环的低级API
    • 2、QThreadPool和QRunnable:重用线程
  • 七、Qt Concurrent:使用高级API
  • 八、WorkerScript:QML的线程
  • 九、选择合适的方法
    • 1、示例使用案例


一、什么是线程?

线程就是并行地做事情,就像进程一样。那么线程和进程有什么不同呢?当您在电子表格上进行计算时,可能会有一个运行在同一桌面上的媒体播放器播放您最喜欢的歌曲。
这是两个进程并行工作的例子:
一个运行电子表格程序;
一个运行媒体播放器。

对此,多任务处理是一个众所周知的术语。仔细观察媒体播放器会发现,在一个进程中又有一些事情在并行进行。当媒体播放器向音频驱动程序发送音乐时,用户界面及其各种功能也在不断更新。这就是线程的用途——在一个进程中实现并发。


那么并发是如何实现的呢?单核CPU上的并行工作是一种错觉,有点类似于电影中的运动图像错觉。对于进程来说,这种错觉是通过在很短的时间后中断处理器在一个进程上的工作而产生的。然后处理器进入下一个进程。为了在进程之间切换,保存当前程序计数器,并加载下一个处理器的程序计数器。这是不够的,因为需要对寄存器和某些架构以及操作系统特定的数据进行同样的处理。


正如一个CPU可以驱动两个或多个进程一样,也可以让CPU在一个进程的两个不同代码段上运行。
当一个进程启动时,它总是执行一个代码段,因此这个进程被称为有一个线程。但是,程序可能会决定启动第二个线程。然后,在一个进程中同时处理两个不同的代码序列。通过重复保存程序计数器和寄存器,然后加载下一个线程的程序计数器和寄存器,可以在单核CPU上实现并发性。在活动线程之间循环不需要来自程序的合作。当切换到下一个线程时,线程可以处于任何状态。


CPU设计的当前趋势是拥有几个核心。典型的单线程应用程序只能使用一个内核。然而,具有多个线程的程序可以被分配到多个内核,使得事情以真正并发的方式发生。因此,将工作分配给多个线程可以使程序在多核CPU上运行得更快,因为可以使用额外的内核。


二、GUI线程和工作线程

如上所述,每个程序在启动时都有一个线程。这个线程被称为“主线程”(在Qt应用中也称为“GUI线程”)。
Qt GUI必须在这个线程中运行。所有小部件和几个相关的类,例如QPixmap,不要在副线程中工作。辅助线程通常被称为“工作线程”,因为它用于从主线程卸载处理工作。

三、同时访问数据

每个线程都有自己的堆栈,这意味着每个线程都有自己的调用历史和局部变量。与进程不同,线程共享相同的地址空间。
下图显示了线程的构造块在内存中的位置。非活动线程程序计数器和寄存器通常保存在内核空间中。每个线程都有一个共享的代码副本和一个单独的堆栈。

在这里插入图片描述

#子线程
worker thread : 工作线程; 辅助线程; 背景工作线程;
program counter : 程序计数器;
register : 寄存器;
#主线程 程序入口
main thread : 主线程; 
program counter : 程序计数器;
register : 寄存器;
#CPU 芯片
program counter : 程序计数器;
register : 寄存器;

#CPU <-> 子线程
cyclical load / unload : 循环加载/卸载

memory : 内存;
kernel space : 内核空间;
________________________________________
user space : 用户空间;
code : 代码段;
stack main : 主栈 (主线程栈区)
stack worker : 工作栈(子线程栈区)

heap :(一般又程序员主动申请)

process : 进程;
_______________________________________
other process : 其他进程;

如果两个线程有一个指向同一个对象的指针,那么两个线程可能会同时访问该对象,这可能会破坏对象的完整性。
当同一个对象的两个方法同时执行时,很容易想象会有多少事情出错。


有时需要从不同的线程访问一个对象;
例如,当生活在不同线程中的对象需要通信时。因为线程使用相同的地址空间,所以线程交换数据比进程更容易、更快。数据不必序列化和复制。传递指针是可能的,但是必须严格协调哪个线程接触哪个对象。必须防止在一个对象上同时执行操作。
有几种方法可以实现这一点,下面介绍其中一些方法。


那么,什么是安全的呢?在一个线程中创建的所有对象都可以在该线程中安全地使用,前提是其他线程没有对它们的引用,并且对象没有与其他线程的隐式耦合。这种隐式耦合可能发生在实例之间共享数据时,如静态成员、单例或全局数据。熟悉…的概念线程安全和可重入类和函数。

四、使用线程

线程基本上有两种用例:

  • 利用多核处理器加快处理速度。
  • 通过卸载持续时间长的处理或阻塞对其他线程的调用,保持GUI线程或其他时间关键型线程的响应。

1、何时使用线程的替代品

开发人员需要非常小心线程。启动其他线程很容易,但很难确保所有共享数据保持一致。问题通常很难发现,因为它们可能只是偶尔出现一次,或者只出现在特定的硬件配置上。在创建线程来解决某些问题之前,应该考虑可能的替代方案。


供选择的评论
QEventLoop::processEvents()QEventLoop::processEvents在耗时的计算过程中重复()可防止GUI阻塞。然而,这种解决方案不能很好地扩展,因为根据硬件的不同,对processEvents()的调用可能太频繁,或者不够频繁。
QTimer后台处理有时可以方便地使用定时器来调度在未来某个时间点的槽的执行。一旦没有更多的事件要处理,间隔为0的计时器就会超时。
QSocketNotifier QNetworkAccessManager qiode device::ready read() 这是拥有一个或多个线程的替代方案,每个线程在慢速网络连接上有一个阻塞读取。只要响应大量网络数据的计算能够快速执行,这种反应式设计就比线程中的同步等待要好。反应式设计比线程设计更不易出错且更节能。在许多情况下,还有性能优势。

一般来说,建议只使用安全且经过测试的路径,并避免引入临时线程概念。这Qt并发模块提供了一个简单的接口,用于将工作分配给处理器的所有内核。线程代码完全隐藏在Qt并发框架,这样就不用管细节了。然而,Qt并发当需要与正在运行的线程进行通信时,不能使用它,并且它不应该用于处理阻塞操作。

2、应该用哪种Qt线程技术?

参见Qt中的多线程技术页面,了解Qt多线程处理的不同方法,以及如何选择这些方法的指南。
上面是官方英文链接,这里我就翻译过来讲

六、Qt中的多线程技术

Qt提供了许多处理线程的类和函数。下面是Qt程序员可以用来实现多线程应用的四种不同方法。

1、QThread:带有可选事件循环的低级API

QThread是Qt中所有线程控制的基础。每个QThread实例表示并控制一个线程。


QThread可以直接实例化,也可以子类化。
实例化QThread提供并行事件循环,允许QObject要在辅助线程中调用的插槽。
子类化QThread允许应用程序在开始事件循环之前初始化新线程,或者在没有事件循环的情况下运行并行代码。

2、QThreadPool和QRunnable:重用线程

频繁地创建和销毁线程可能代价很高。为了减少这种开销,现有线程可以重新用于新任务。QThreadPool是可重用QThreads的集合。


在其中一个QThreadPool’s线程,重新实现QRunnable::run()并实例化子类QRunnable。使用QThreadPool::start()QRunnable在QThreadPool’s运行队列。当线程变得可用时,其中的代码QRunnable::run()将在该线程中执行。


每个Qt应用程序都有一个全局线程池,可以通过QThreadPool::globalInstance().这个全局线程池根据CPU中核心的数量自动维护最佳的线程数量。然而,一个单独的QThreadPool可以显式地创建和管理。


七、Qt Concurrent:使用高级API

Qt Concurrent模块提供了处理一些常见并行计算模式的高级函数:映射、过滤和归约
不同于使用QThreadQRunnable,这些函数从不需要使用低级线程原语例如互斥或信号量。相反,它们返回一个QFuture对象,该对象可用于在函数准备就绪时检索函数的结果。QFuture也可用于查询计算进度和暂停/恢复/取消计算。为了方便起见,QFutureWatcher支持与以下对象的交互QFuture通过信号和插槽。


Qt Concurrent’s的mapfilterreduce算法会自动在所有可用的处理器内核之间分配计算,因此,今天编写的应用程序将在以后部署到具有更多内核的系统上时继续扩展。

本模块还提供了QtConcurrent::run()函数,可以运行另一个线程中的任何函数。然而,QtConcurrent::run()仅支持可用于映射过滤归约功能的功能子集。
QFuture可用于检索函数的返回值并检查线程是否正在运行。然而,调用QtConcurrent::run()仅使用一个线程,不能暂停/恢复/取消,也不能查询进度。

八、WorkerScript:QML的线程

WorkerScript QML类型让JavaScript代码与GUI线程并行运行。

每个WorkerScript实例可以有一个.js附在它上面的脚本。当WorkerScript.sendMessage()被调用时,脚本将在一个单独的线程(和一个单独的QML背景).当脚本完成运行时,它可以向GUI线程发送一个回复,该线程将调用WorkerScript.onMessage()信号处理器。

九、选择合适的方法

如上所述,Qt为开发线程化应用提供了不同的解决方案。给定应用程序的正确解决方案取决于新线程的用途和线程的生命周期。下面是Qt线程技术的比较,以及一些示例用例的推荐解决方案。


在这里插入图片描述
在这里插入图片描述

1、示例使用案例

线程的寿命操作解决办法
单次调用在另一个线程中运行一个新的线性函数,可选地在运行期间进行进度更新。Qt提供不同的解决方案:【1】将函数放在的重新实现中QThread::run()并启动QThread。发出信号以更新进度。【2】将函数放在的重新实现中QRunnable::run()并添加QRunnableQThreadPool。写信给线程安全变量更新进度。【3】使用运行该函数QtConcurrent::run().写信给线程安全变量更新进度。
单次调用在另一个线程中运行现有函数,并获取其返回值。使用运行该函数QtConcurrent::run().有一个QFutureWatcher发出finished()当函数返回时发出信号,并调用QFutureWatcher::result()获取函数的返回值。
单次调用使用所有可用的核心对容器中的所有项目执行操作。例如,从图像列表中生成缩略图。使用Qt并发QtConcurrent::filter()函数来选择容器元素,而QtConcurrent::map()函数将运算应用于每个元素。要将输出合并成一个结果,请使用QtConcurrent::filteredReduced()QtConcurrent::mappedReduced()取而代之。
单次调用/永久调用在纯QML应用程序中执行长时间的计算,并在结果准备好时更新GUI。将计算代码放在.js脚本并将其附加到WorkerScript实例。调用WorkerScript.sendMessage()在新线程中开始计算。让脚本也调用sendMessage(),将结果传递回GUI线程。处理结果onMessage并在那里更新GUI。
永久调用让一个对象驻留在另一个线程中,该线程可以根据请求执行不同的任务和/或可以接收新数据进行处理。子类QObject创造一个任务。实例化该工作对象和一个QThread。将工作线程移至新线程。通过排队的信号插槽连接向任务对象发送命令或数据。
永久调用在另一个线程中重复执行开销较大的操作,该线程不需要接收任何信号或事件。直接在的重新实现中编写无限循环QThread::run().在没有事件循环的情况下启动线程。让线程发出信号将数据发送回GUI线程。

后续安排例子

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

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

相关文章

集成学习以及随机森林介绍

一、集成学习简介 1.什么是集成学习&#xff1f; 集成学习&#xff08;Ensemble Learning&#xff09;是一种机器学习方法&#xff0c;通过将多个弱学习器&#xff08;weak learner&#xff09;组合在一起来构建一个更强大的学习器&#xff08;strong learner&#xff09;。 …

C语言进阶——字符函数和字符串函数(下)

在前面我们已经学习了strlen、strcpy、strcat、strcmp几个库函数&#xff0c;今天我们继续学习剩余的库函数。 上期链接&#xff1a; C语言进阶——字符函数和字符串函数&#xff08;上&#xff09;_wangjiushun的博客-CSDN博客 目录&#xff1a; 3、长度受限制的字符串函数…

Redis(四)持久化策略

文章目录 持久化策略1、为什么Redis需要持久化2、Redis提供的两种持久化方式(1)RGB持久化详解概述RGB持久化的两种触发策略手动触发实例测试&#xff1a;自动触发实例测试&#xff1a; 查看rdb的状态信息info Persistence rdb模式的优缺点 (2)AOF持久化详解AOF持久化步骤&#…

近期复盘 | 想多了都是问题,想开了都是答案

文章目录 &#x1f339;四月坚持背单词&#xff0c;五月坚持利用AI写文章&#x1f60a;六月会坚持干什么&#x1f64c;23年7月&#xff1a;毕业两年&#xff0c;参保两年&#x1f440;强制存储&#xff0c;消费降级&#xff0c;开源节流&#x1f61c;好好深耕能力&#x1f381;…

JavaScript 进阶 (一)

目录 作用域 局部作用域 函数作用域 块作用域 全局作用域 作用域链 JS垃圾回收机制 闭包 变量提升 函数进阶 函数提升 函数参数 箭头函数 基本语法 箭头函数参数 箭头函数this 解构赋值 数组解构 对象解构 遍历数组 forEach 方法&#xff08;重点&#xff09; …

shell SNAT与DNAT

文章目录 SNATSNAT原理与应用SNAT实验 DNATDNAT原理与应用DNAT实验 SNAT SNAT原理与应用 SNAT 应用环境&#xff1a;局域网主机共享单个公网IP地址接入Internet&#xff08;私有不能早Internet中正常路由&#xff09; SNAT原理&#xff1a;修改数据包的源地址。 SNAT转换前提…

文心一言 VS 讯飞星火 VS chatgpt (23)-- 算法导论4.2 5题

五、V.Pan 发现一种方法&#xff0c;可以用 132 464 次乘法操作完成 68 x 68 的矩阵相乘&#xff0c;发现另一种方法&#xff0c;可以用 143 640 次乘法操作完成 70 x 70 的矩阵相乘&#xff0c;还发现一种方法&#xff0c;可以用155 424次乘法操作完成 72 x 72 的矩阵相乘。当…

数据安全治理科技产品能力-数据安全复合治理框架和模型解读(2)

数据治理,数据安全治理行业在发展,在实践,所以很多东西是实践出来的,哪有什么神仙理论指导,即使有也是一家之说,但为了提高企业投产比,必要的认知是必须的,落地数据安全治理科技水平差异直接决定产品和项目是否可持续性,当前和未来更需要专业和有效创新。数据安全治理…

自动驾驶业内动态简讯

1. 引言 参与自动驾驶领域相关研发工作已有多年&#xff0c;针对该领域的快速发展&#xff0c;收集业内各大科技公司最新进展和技术突破&#xff0c;供伙伴们交流探讨。 闲话少说&#xff0c;直接开始吧! 2. 博世 据新闻介绍&#xff0c;博世在德国道路上测试L4级无人驾驶汽…

java 区分缺陷Defects/感染Infections/失败Failure

java 区分缺陷Defects/感染Infections/失败Failure 缺陷Defects 软件故障总是从代码中一个或多个缺陷的执行开始。 缺陷只是一段有缺陷、不正确的代码。 缺陷可能是程序语句的一部分或完整部分&#xff0c;也可能对应于不存在但应该存在的语句。 尽管程序员要对代码中的缺陷负…

基于SSM的甜品店商城系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 随着社会经济的发展和…

Altium Designer 相同电路多组复制布线

在进行设计开发的时候&#xff0c;总会遇到相同的电路&#xff0c;或者模块&#xff0c;这些电路可以使用相同的布局和走线。我们可以画好其中一部分&#xff0c;然后直接复制&#xff0c;就可以提高效率。下面记录我自己的实际操作过程&#xff0c;有一些地方遇到了问题&#…

Android | Android OS 源码结构

参考&#xff1a;AndroidXRef (http://androidxref.com/)版本&#xff1a;Pie - 9.0.0_r3 整体结构 对于 Android OS 的源码目录来说&#xff0c;各个版本的结构大同小异&#xff0c;随不同版本特性会有个别目录差异。编译后会额外产生一个 out 文件夹用于存储编译产生的文件。…

Unity使用SteamVR2.0实现基本功能(瞬移,抓取物品,射线点击,UI交互等)

基础设置 把SteamVR的Player预制件拖到一个空场景,删掉场景内原本的相机 一.瞬移 新建一个Plane,当做地板找到SteamVR的人物瞬移控制器 Teleporting ,把它拖到场景里 1. 范围移动 我们需要在可以移动的区域,也就是碰撞器上,挂TeleportArea脚本 这个脚本会自动修改你的材质球…

抖音seo源码--开源,支持二开不加密

抖音seo源码&#xff0c;抖音seo矩阵系统源码技术搭建&#xff0c;抖音seo源码技术开发思路梳理搭建 开发思路&#xff1a; 抖音seo源码如何搭建&#xff1f;抖音seo排名优化系统软件部分源码分析&#xff0c;代码打包中。。。 场景&#xff1a;在 python 中&#xff0c;你可…

windows下修改PyCharm默认terminal 在Git Bash中使用conda

windows下修改PyCharm默认terminal & 在Git Bash中使用conda windows下修改PyCharm默认terminal在Git Bash中使用conda windows下修改PyCharm默认terminal PyCharm的terminal默认使用的是powershell&#xff0c;但是conda环境是通过cmd运行的&#xff0c;因此可以将PyChar…

安捷伦N5182A是德KEYSIGHT N5182B 100KHZ至3G/6G信号发生器

Agilent N5182A、Keysight N5182A MXG 射频矢量信号发生器&#xff0c;100 kHz - 3 GHz 或 6 GHz ​Keysight N5182A (Agilent) MXG 射频矢量信号发生器具有快速频率、幅度和波形切换、带电子衰减器的高功率和高可靠性 – 所有这些都集成在两个机架单元 (2RU) 中。Keysight N5…

H743 USBHOST协议栈 CPU占用率高的问题。

经过查看&#xff0c;是因为USBHOST频繁的进入中断导致&#xff0c;单步执行发现&#xff0c;是因为发生了USB_OTG_HCINT_CHH或者USB_OTG_HCINT_NAK中断了&#xff0c;只在CHH中断服务函数里&#xff0c;给USB主线程发了1个消息&#xff0c;又引起了USBH_Process_OS主线程的频繁…

YOLOV7训练TT100K交通标识符数据集

《临江仙》 作者&#xff1a;缠中说禅 浊水倾波三万里&#xff0c;愀然独坐孤峰。龙潜狮睡候飙风。无情皆竖子&#xff0c;有泪亦英雄。 长剑倚天星斗烂&#xff0c;古今过眼成空。乾坤俯仰任穷通。半轮沧海上&#xff0c;一苇大江东。 一、yolov7环境搭建 参…

【内网穿透】远程访问RabbitMQ服务

文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 转载自cpolar内网穿透的文章&#xff1a;无公网IP&…