QtC++使用QRunnable+QThreadPool管理多线程
本文的示例项目工程在文章最后有分享链接,可以下载运行试试。下载后替换成自己的Qt版本即可(项目 -> 属性 -> 配置属性 -> Qt Project Settings -> Qt Installation)
应用场景介绍
现有一个应用场景,需要进行上千个循环里面,调用相同的功能类去计算,只使用一个线程去计算,效率太低,结合网络上的帖子和自身实践。我的实现场景如下:
- 界面类Dialog。给用户提供交互操作
- 计算类Logic。执行用户点击后的计算逻辑
- 任务类QRunnable。在若干循环里面用于完成指定任务
运行过程
在Qt界面中,用户点击某个控件后,创建一个线程去执行计算操作,避免界面阻塞,陷入卡死。
(这里有个不继承 qthread 使用多线程的方法,提供另一种实现方法思路)
QThread*mThread;//!< 计算类执行的线程Calculate*mCalculate;//!< 计算类,放在mThread线程里面执行,避免界面卡死/************************************************************************//* 上面为成员变量 *//************************************************************************/mThread=newQThread();mCalculate=newCalculate();mCalculate->moveToThread(mThread);// 改变mCalculate的线程依附关系,将计算类放在线程中执行//! 释放堆空间资源,避免内存泄露connect(mThread,&QThread::finished,mThread,&QObject::deleteLater);connect(mThread,&QThread::finished,mCalculate,&QObject::deleteLater);//! 注意:在使用跨线程通信时,参数需要为元数据类型(具体我也解释不清楚,理解是有关 meta 什么的)qRegisterMetaType<CalculateInputStruct>("CalculateInputStruct");// 将结构体 CalculateInputStruct 注册为元数据类型//! 连接其他信号槽,用于触发线程执行槽函数里的任务connect(this,&MultiThreadDemo::StartCalculate,mCalculate,&Calculate::startCalculateSlot,Qt::QueuedConnection);// 默认使用Qt::QueuedConnection,保证槽函数的执行顺序connect(mCalculate,&Calculate::CalculateFinished,this,&MultiThreadDemo::calculate_finished_slot,Qt::QueuedConnection);// 计算完成显示信息connect(mCalculate,&Calculate::UpdateProssorbar,this,&MultiThreadDemo::update_prossorbar_slot,Qt::QueuedConnection);// 每计算一次完一次任务,更新界面进度条mThread->start();// 启动线程,线程默认开启事件循环,并且线程正处于事件循环状态类似Run函数实现
计算类使用 qthreadpool 线程池实现,这里的任务是独立的,每个计算任务仅使用传递的参数,没有涉及资源共享
voidCalculate::startCalculateSlot(constCalculateInputStruct aInput){autotest_thread_id=QThread::currentThreadId();// 查看当前线程的id和界面类、任务类的id是否相同QThreadPool thread_pool;thread_pool.setMaxThreadCount(aInput.threadMaxCount);// 设置线程池的最大线程数为1for(inti=0;i<aInput.calculateCount;i++){CalculateRunnable*runnable=newCalculateRunnable;runnable->setAutoDelete(true);// 设置任务结束后自动删除thread_pool.start(runnable);//! 设置响应方式为消息队列时,会在emit CalculateFinished(); 后再响应,故这里使用直接响应connect(runnable,&CalculateRunnable::RunnableFinished,this,[&](){emitUpdateProssorbar();},Qt::DirectConnection);}thread_pool.waitForDone();// 等待所有任务完成emitCalculateFinished();}}结果对比
一个任务类在run函数中的计算为0.5s。可以看出,理论上线程池中还是有效的。
参考
在寻找答案的过程中,看了很多帖子,分享几遍个人觉得质量不错的文章
- Qt多线程通信
- Qt线程之QRunnable的使用详解
- QT 多线程的实现方法以及GUI线程与其他线程间的通信
- 【QT】子类化QObject+moveToThread实现多线程
- Qt使用多线程的一些心得——1.继承QThread的多线程使用方法
工程示例
- 开发环境:Qt5.15.2 + vs2022
- csdn链接:https://download.csdn.net/download/weixin_51238542/90291812
- 百度网盘链接:https://pan.baidu.com/s/1JkKm6QF1TrFbQbgyaPqZSw?pwd=tvhn
- github链接:https://github.com/tianxingithub/MultiThreadDemo
