Qt 多线程 QThread、QThreadPool使用场景
QThread 和 QRunnable 都是 Qt 框架中用于多线程编程的类,它们之间有以下不同点:
-
继承关系不同
QThread 继承自 QObject 类,而 QRunnable 没有父类。 -
实现方式不同
QThread 是一个完整的线程实现,包含了线程的创建、启动、停止、等待等功能。而 QRunnable 是一个任务接口,需要在 QThread 中使用 QThreadPool 或者手动创建线程池来执行任务。 -
线程数控制不同
使用 QThread 时,需要手动创建线程,因此可以直接控制线程数。而使用 QThreadPool 和 QRunnable 时,线程池会自动管理线程,可以通过设置最大线程数来控制并发执行的任务数。 -
取消任务的方式不同
使用 QThread 时,可以通过调用 QThread 的 quit() 方法或者设置一个标志位来取消线程的执行。而在 QRunnable 中,需要使用 QThreadPool 的 cancel() 方法来取消任务的执行。
总的来说,QThread 适用于需要自行管理线程的情况,比如需要控制线程的生命周期、线程间通信等情况。而 QRunnable 和 QThreadPool 适用于需要管理一组任务的情况,比如大量短时间的计算任务、网络请求等。使用 QThreadPool 和 QRunnable 可以有效地管理线程池和任务队列,避免创建过多的线程导致系统负载过高。
QThread
优点:
可以使用信号槽进行通信
缺点:
需要自己管理资源,线程的创建和释放,都需要自己手动管理,并且,频繁的创建和删除会造成比较大的内存开销。
适用场景:
线程不会被频繁的创建和删除,常驻内存的线程。
QThread 有两种使用方式:
- 通过moveToThread()实现 (qt开发者更推荐的方式)
- 通过子类继承QThread实现
moveToThread方式
#include <iostream>
#include <QThread>
#include <QDebug>
using namespace std;class worker : public QObject {Q_OBJECT
public slots:void doWork(const QString ¶meter) {qDebug() << "work Thread ID:" << QThread::currentThreadId();QString result;emit resultReady(result);}signals:void resultReady(const QString& result);
};class controller : public QObject {Q_OBJECT
public:controller() {worker* w = new worker();w->moveToThread(&_thread);connect(&_thread, &QThread::finished, w, &QObject::deleteLater);connect(this, &controller::begin, w, &worker::doWork);connect(w, &worker::resultReady, this, &controller::handleResults);_thread.start();}~controller() {_thread.quit();_thread.wait();}public slots:void handleResults(const QString& result) { cout << "I'm handleResult" << endl; }signals:void begin(const QString& parameter);private:QThread _thread;
};
/************测试**************/
#include <QCoreApplication>int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);qDebug() << "main Thread ID: " << QThread::currentThreadId();controller c;emit c.begin("");return app.exec();
}
//输出
main Thread ID: 0x6848
work Thread ID: 0x5724
I'm handleResult
子线程必须在 event loop 里执行,因为子线程是由主线程创建的,如果主线程退出了,子线程会也会立即退出。不管是否执行完。
子类继承QThread方式
#include <iostream>
#include <QThread>
#include <QDebug>
using namespace std;class myThread : public QThread {Q_OBJECT
public:myThread() {connect(this, &myThread::finished, this, &myThread::deleteLater);}void run() override {QString result;qDebug() << "sub Thread ID:" << QThread::currentThreadId();// do somethingemit resultReady(result);}signals:void resultReady(const QString&);
};class myObject : public QObject {Q_OBJECT
public:myObject() {myThread *mt = new myThread();connect(mt, &myThread::resultReady, this, &myObject::handleResult);mt->start();}
public slots:void handleResult(const QString& result) { cout << "I'm handleResult" << endl; }
};
/**********测试******************/
#include <QCoreApplication>int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);qDebug() << "main Thread ID: " << QThread::currentThreadId();myObject mo;return app.exec();
}//输出
main Thread ID: 0x639c
sub Thread ID: 0x75ec
I'm handleResult
注意:
实例化的子类是在创建线程的旧线程中,不是在新创建的子线程中,该线程的槽函数还是在主线程执行,所以, 不能直接在新建的线程中使用槽。要想在子线程执行槽函数,只能用moveToThread方式
实例化子类的构造函数和run()函数在不同的线程中运行,因此,假设有成员变量两个函数中都能访问,则需要注意,多线程中资源的访问问题。
QThreadPool与QRunnable
优点:
不用资源管理,QThreadPool 启动线程执行完成后会自动释放
缺点:
可能会形成多线程资源竞争
不能使用信号槽(可以通过继承QObject中使用)
适用场景:
QRunnable适用于线程任务量比较大,需要频繁创建线程的情况。QRunnable能有效减少内存开销。
代码示例
头文件:
#include <QRunnable>
#include <QThread>
#include <QDebug>
#include <QThreadPool>
#include <QSemaphore>using namespace std;class taskQueue {friend class worker;
public:taskQueue(bool useThread);void calculate();private:void doTask(int i);private:QThreadPool* _pool;bool _useThread;QSemaphore _sema;
};class worker : public QRunnable {
public:worker(taskQueue* task, int parameter);void run() override;
private:taskQueue* _task;int _parameter;
};
源文件:
taskQueue::taskQueue(bool useThread) : _useThread(useThread) {if (_useThread) {_pool = QThreadPool::globalInstance();_sema.release(QThread::idealThreadCount());}
}void taskQueue::calculate() {for (int i = 0; i < 10; i++) {if (_useThread) {_sema.acquire(); //当线程不够时,等待线程任务完成_pool->start(new worker(this, i));} else {doTask(i);}}_pool->waitForDone();
}void taskQueue::doTask(int i) {// do somethingqDebug() << i << "sub thread" << QThread::currentThreadId();_sema.release();
}worker::worker(taskQueue *task, int parameter): _task(task), _parameter(parameter) {}void worker::run() {_task->doTask(_parameter);
}
/************测试***********/
int main(int argc, char *argv[])
{qDebug() << "main Thread ID: " << QThread::currentThreadId();taskQueue q(1);q.calculate();
}
//输出
main Thread ID: 0x4d3c
2 sub thread 0x5d18
1 sub thread 0x5a68
3 sub thread 0x3d4
4 sub thread 0x4ae0
6 sub thread 0x4f50
8 sub thread 0x480c
0 sub thread 0x7888
7 sub thread 0x2734
5 sub thread 0x7c10
9 sub thread 0x4c98
QtConcurrent
QtConcurrent是一个命名空间,提供了一些高级的 API,使得在编写多线程的时候,无需使用低级线程原语,如读写锁,等待条件或信号。使用QtConcurrent编写的程序会根据可用的处理器内核数自动调整使用的线程数。这意味着今后编写的应用程序将在未来部署在多核系统上时继续扩展。
QtConcurrent::run能够方便快捷的将任务丢到子线程中去执行,无需继承任何类,也不需要重写函数,使用非常简单。
run函数:
template <typename T>
QFuture<T> QtConcurrent::run(Function function, ...)template <typename T>
QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...)
不传线程池的相当于:
QtConcurrent::run(QThreadPool::globalInstance(), function, ...);
QtConcurrent 的底层实现是 QThreadPool与QRunnable
相关文章:

Qt 多线程 QThread、QThreadPool使用场景
QThread 和 QRunnable 都是 Qt 框架中用于多线程编程的类,它们之间有以下不同点: 继承关系不同 QThread 继承自 QObject 类,而 QRunnable 没有父类。 实现方式不同 QThread 是一个完整的线程实现,包含了线程的创建、启动、停止、…...

如何一招搞定PCB阻焊过孔问题?
PCB阻焊油墨根据固化方式,阻焊油墨有感光显影型的油墨,有热固化的热固油墨,还有UV光固化的UV油墨。而根据板材分类,又有PCB硬板阻焊油墨,FPC软板阻焊油墨,还有铝基板阻焊油墨,铝基板油墨也可以用…...

【代码随想录】刷题Day2
1.左右指针比大小 977. 有序数组的平方 class Solution { public:vector<int> sortedSquares(vector<int>& nums) {vector<int> ret nums;int left 0;int right nums.size()-1;int end nums.size();while(left<right){if(abs(nums[left])>abs…...

Python机器学习、深度学习技术提升气象、海洋、水文领域实践应用
Python是功能强大、免费、开源,实现面向对象的编程语言,在数据处理、科学计算、数学建模、数据挖掘和数据可视化方面具备优异的性能,这些优势使得Python在气象、海洋、地理、气候、水文和生态等地学领域的科研和工程项目中得到广泛应用。可以…...

计及调度经济性的光热电站储热容量配置方法【IEEE30节点】(Matlab代码实现)
💥 💥 💞 💞 欢迎来到本博客 ❤️ ❤️ 💥 💥 🏆 博主优势: 🌞 🌞 🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 …...

“不要放过这个春天”解锁品牌春日宣传新玩法
在万物复苏的春天,人们换新装、踏青等需求蓄势待发,出现了全民消费热情高涨的趋势,让品牌「贩卖春天」的宣传此起彼伏。 品牌洞察到用户的消费需求,打造具有品牌特色的浪漫宣传,如采用春日限定元素、创新春天宣传场景…...

利用GPT2 预测 福彩3d预测
使用GPT2预测福彩3D项目 个人总结彩票数据是随机的,可以预测到1-2个数字,但是有一两位总是随机的 该项目紧做模型学习用,通过该项目熟练模型训练调用生成过程. 福彩3D数据下载 https://www.17500.cn/getData/3d.TXT data数据格式 处理后数据格式 每行 2023 03 08 9 7 3 训…...

类加载过程
基本说明 反射机制是Java实现动态语言的关键,也就是通过反射实现类动态加载。 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强动态加载:运行时加载需要的类,如果运行时不用该类,即使…...

【C/C++】C++11 无序关联容器的诞生背景
文章目录 背景无序关联容器适用场景有序关联容器适用场景 背景 C11 引入了无序关联容器(unordered_map、unordered_set、unordered_multimap 和 unordered_multiset)是为了提供一种高效的元素存储和查找方式。相比于有序关联容器(map、set、…...

h264编码原理
在介绍编码器原理之前首先了解三个制定编码标准的组织: 1.国际电信联盟(ITU-T),这是一个音视频领域非常强的组织,规定了很多标准如h261,h262,h263,h263。h263也就是h264的前身。 2.国际标准化组织(ISO)&…...

网络工程师经常搞混的路由策略和策略路由,两者到底有啥区别?
当涉及到网络路由时,两个术语经常被混淆:策略路由和路由策略。虽然这些术语听起来很相似,但它们实际上有着不同的含义和用途。在本文中,我们将详细介绍这两个术语的区别和应用。 一、路由策略 路由策略是指一组规则,用…...

高精度气象模拟软件WRF实践技术
【原文链接】:高精度气象模拟软件WRF(Weather Research Forecasting)实践技术及案例应用https://mp.weixin.qq.com/s?__bizMzU5NTkyMzcxNw&mid2247538149&idx3&sn3890c3b29f34bcb07678a9dd4b9947b2&chksmfe68938fc91f1a99bbced2113b09cad822711e7f…...

总结827
学习目标: 4月(复习完高数18讲内容,背诵21篇短文,熟词僻义300词基础词) 学习内容: 高等数学:刷1800,做了26道计算题,记录两道错题,搞懂了,但并不…...

还在发愁项目去哪找?软件测试企业级Web自动化测试实战项目
今天给大家分享一个简单易操作的实战项目(已开源) 项目名称 ET开源商场系统 项目描述 ETshop是一个电子商务B2C电商平台系统,功能强大,安全便捷。适合企业及个人快速构建个性化网上商城。 包含PCIOS客户端Adroid客户端微商城…...

总结下Spring boot异步执行逻辑的几种方式
文章目录 概念实现方式Thread说明 Async注解说明 线程池CompletableFuture(Future及FutureTask)创建CompletableFuture异步执行 消息队列 概念 异步执行模式:是指语句在异步执行模式下,各语句执行结束的顺序与语句执行开始的顺序…...

【开发日志】2023.04 ZENO----Composite----CompNormalMap
NormalMap-Online (cpetry.github.io)https://cpetry.github.io/NormalMap-Online/ CompNormalMap 将灰度图像转换为法线贴图 将灰度图像转换为法线贴图是一种常见的技术,用于在实时图形渲染中增加表面细节。下面是一个简单的方法来将灰度图像转换为法线贴图&…...

春秋云境:CVE-2022-28525 (文件上传漏洞)
目录 一、题目 1.登录 2.burp抓包改包 3.蚁剑获取flag 一、题目 ED01CMSv20180505存在任意文件上传漏洞 英语不够 翻译来凑: 点击其他页面会Not Found 找不到: 先登录看看吧: 试试万能密码:admin:123 发现错误…...

【软件测试二】开发模型和测试模型,BUG概念篇
目录 1.软件的生命周期 2.瀑布模型 3.螺旋模型 4.增量,迭代 5.敏捷---scrum 1. 敏捷宣言 2.角色 6. 软件测试v模型 7.软件测试w模型 8.软件测试的生命周期 9.如何描述一个BUG 10.如何定义BUG的级别 11.BUG的生命周期 12.产生争执怎么办 1.软件的生命周期…...

短视频app开发:如何实现视频直播功能
短视频源码的实现 在短视频app开发中,实现视频直播功能需要借助短视频源码。短视频源码可以提供一个完整的视频直播功能模块,包括视频采集、编码、推流等。因此,我们可以选择一些开源的短视频源码,例如LFLiveKit、ijkplayer等&am…...

[架构之路-174]-《软考-系统分析师》-5-数据库系统-7-数据仓库技术与数据挖掘技术
5 . 7 数据仓库技术 数据仓库是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合,用于支持管理决策。近年来,人们对数据仓库技术的关注程度越来越尚,其原因是过去的几十年中,建设了无数的应用系统,积累了…...

销售高品质 FKM EPDM NBR 硅胶 O 形密封圈
O形圈常用于各种行业,包括汽车、航空航天和制造业。它们是由不同材料制成的圆环,用于将两个或多个组件密封在一起。用于制造O形圈的材料是决定其有效性和耐用性的重要因素。在本文中,我们将讨论用于制作O形圈的不同类型的材料。 1.丁腈橡胶(…...

Linux环境变量:不可或缺的系统组成部分
目录标题 引言(Introduction)Linux环境变量的概念(Concept of Linux Environment Variables)环境变量的作用与重要性(Roles and Importance of Environment Variables) Linux环境变量基础(Linux…...

FFmpeg命令行解析
目录标题 一、引言(Introduction)1.1 FFmpeg简介(Overview of FFmpeg)1.2 FFmpeg命令行的应用场景(Application Scenarios of FFmpeg Command Line) 二、FFmpeg命令行基础(FFmpeg Command Line …...

机器学习——为什么逻辑斯特回归(logistic regression)是线性模型
问:逻辑斯蒂回归是一种典型的线性回归模型。 答:正确。逻辑斯蒂回归是一种典型的线性回归模型。它通过将线性回归模型的输出结果映射到[0,1]区间内,表示某个事物发生的概率,从而适用于二分类问题。具体地说,它使用sig…...

从输入URL到页面展示到底发生了什么
刚开始写这篇文章还是挺纠结的,因为网上搜索“从输入url到页面展示到底发生了什么”,你可以搜到一大堆的资料。而且面试这道题基本是必考题,二月份面试的时候,虽然知道这个过程发生了什么,不过当面试官一步步追问下去的…...

Qt connect传参方式及lambda函数传参方式详解
Qt connect传参方式及lambda函数传参方式详解 Qt是一种流行的跨平台C应用程序框架,它提供了许多有用的工具和函数来帮助开发人员构建高效的图形用户界面和其他应用程序。其中,Qt Connect函数是用于连接信号和槽的重要函数之一,它可以在Qt应用…...

如何在硬盘上恢复已经删除的照片?
可以从硬盘恢复删除的照片吗? 旅行后,许多人倾向于将照片保存到另一个储存设备作为副本或备份。例如,将它们存储在外部硬盘上或将图片传输到电脑。但是在整理照片的时候,很可能不小心把照片删掉了,尤其是使用外接硬…...

Unity日记22(携程概念)
目录 学习视频 携程 1异步 2调用方法 3优点 4停止方法 5返回值 实例:每过一秒打印当前运行时间 实例:停止数字打印携程 错误方法:(携程只能开一个) 参考方法 学习视频 https://www.bilibili.com/video/BV1eu…...

01-Linux-磁盘分区与目录配置
1. 主引导纪录和磁盘分区表 1.1 MBR分区表 启动引导程序记录区与分区表都放在磁盘的第一个扇区(512B) 由于分区表仅占 64B,因此最多能有四组记录区,每组记录区记录了该区段的起始与结束的柱面号码。 缺点如下: 操作…...

连接器信号完整性仿真教程 二
在连接器信号完整性仿真教程一中Step by Step演示了如何进行连接器信号完整性仿真,看完这片博文后应该可以做类似产品的仿真。如果说,看了这篇博文就学会了连接器信号完整性仿真,那就有点过了。有人也许会说信号完整性仿真难学,不…...