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 数据仓库技术 数据仓库是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合,用于支持管理决策。近年来,人们对数据仓库技术的关注程度越来越尚,其原因是过去的几十年中,建设了无数的应用系统,积累了…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...
【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?
FTP(File Transfer Protocol)本身是一个基于 TCP 的协议,理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况,主要原因包括: ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...