QT6线程池的使用QThreadPool
前面介绍了多线程的使用,这次主要介绍线程池的使用。
线程池主要解决了两个问题:
1、因为过多的new thread会占用太多的资源,最终可能会导致服务器因资源不足而宕机;
2、频繁的创建、销毁线程也会消耗服务器性能而最终影响了程序的执行效率。
简单解释就是不固定数量的new thread可能会把机器的内存、网络带宽等资源消耗干净,或者每1或几分钟(秒钟)周期内(反复)执的线程new和delete会影响执行效率。
如果出现以上的两种情况,就推荐使用线程池来管理线程。那么具体应该如何使用Qt的线程池呢?
实现多线程一共有六步
- 创建任务类,继承QRunable和QObject
- 实现任务类,重写run()方法
- 设定任务类是否自动释放内存
- 在主线程中,创建任务对象
- 设置最大线程数setMaxThreadCount
- 使用start()启动线程
本案例的流程图
1、创建任务类
- 定义了一个任务类,在Task中,实现循环N次,返回M毫秒
- 继承QRunable和QObject,重写run()方法
myThread.h,全部代码
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
#include <QRunnable>
class Task:public QObject, public QRunnable
{
Q_OBJECT
public:
explicit Task(QObject *parent = nullptr);
void receNum(int num);
signals:
void working(int num);
void finish(QString elapsedTime);
protected:
void run() override;
private:
int iRecvNum;
};
#endif // MYTHREAD_H
2、实现任务类,重写run方法
- receNum方法,用来接收主线程的参数
- run方法实现线程内的业务处理
myThread.cpp,全部代码
#include "myThread.h"
#include <QElapsedTimer>
#include <QDebug>
#include <QThread>
Task::Task(QObject *parent) : QObject(parent), QRunnable()
{
//设置自动析构
setAutoDelete(false);
}
void Task::receNum(int num)
{
iRecvNum=num;
}
void Task::run(){
qDebug() <<" 线程:"<< iRecvNum<<" || "<<QThread::currentThread();
QElapsedTimer time;
time.start();
for(int i=0;i<iRecvNum;i++){
QThread::msleep(1); // 处理任务
emit working(i);
}
qDebug() <<"线程,共耗时: "<<time.elapsed() <<" ms。";
emit finish(QString::number(time.elapsed()));
}
3、设定任务类是否自动释放内存
- 该设置在上面的myThread.cpp中;
- 因为项目中定义的是三个任务对象数组,所以设置为flase,默认为true
//设置自动析构
setAutoDelete(false);
4. 在主线程中,创建任务对象
在QMainWindow.h文件中
- 定义三个信号函数(transParam1,transParam1和transParam3),以方便向三个线程内传值,信号函数只需声明,不用实现。
- 创建了三个线程对象,Task *work =new Task[3];
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "myThread.h"
#include <QThread>
#include <QThreadPool>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_startButton_clicked();
signals:
void transParam1(int num);
void transParam2(int num);
void transParam3(int num);
private:
Ui::MainWindow *ui;
//创建任务类的对象
Task *work =new Task[3];
Task *task =new Task;
int returnValue[2]={0};
};
#endif // MAINWINDOW_H
5、设置最大线程数setMaxThreadCount
在MainWindow.cpp中
- 通过setMaxThreadCount设置最大线程数,也可以理解为同时执行的最大线程数
- 设置好最大线程数可以有效利用服务器资源和程序执行效率
//设置线程数
QThreadPool::globalInstance()->setMaxThreadCount(1);
}
6. 使用start()启动线程
- 使用QThreadPool::globalInstance()->start(&work[0])来启动线程
- 启动线程后,任务对象有可能不会立即执行,而是会根据刚才设置的最大线程数在线程池中排队执行
MainWindow.cpp,全部代码
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include "myThread.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QThreadPool::globalInstance()->setMaxThreadCount(1);
//给子线程传值
connect(this,&MainWindow::transParam1,&work[0],&Task::receNum);
connect(this,&MainWindow::transParam2,&work[1],&Task::receNum);
connect(this,&MainWindow::transParam3,&work[2],&Task::receNum);
//接收子线程发送的数据,并更新进度条
connect(&work[0],&Task::working,this,[=](int l){
ui->thread1_Bar->setValue(l);
ui->thread1_Bar->update();
});
connect(&work[1],&Task::working,this,[=](int l){
ui->thread2_Bar->setValue(l);
ui->thread2_Bar->update();
});
connect(&work[2],&Task::working,this,[=](int l){
ui->thread3_Bar->setValue(l);
ui->thread3_Bar->update();
});
connect(&work[0],&Task::finish,this,[=](QString s){
ui->thread1_Edit->setText(s);
returnValue[0]=s.toInt();
if(returnValue[1]>0){
ui->thread3_Bar->setMaximum(returnValue[0]+returnValue[1]);
emit transParam3(returnValue[0]+returnValue[1]);
QThreadPool::globalInstance()->start(&work[2]);
}
});
connect(&work[1],&Task::finish,this,[=](QString s){
ui->thread2_Edit->setText(s);
returnValue[1]=s.toInt();
if(returnValue[0]>0){
ui->thread3_Bar->setMaximum(returnValue[0]+returnValue[1]);
emit transParam3(returnValue[0]+returnValue[1]);
QThreadPool::globalInstance()->start(&work[2]);
}
});
connect(&work[2],&Task::finish,this,[=](QString s){
ui->thread3_Edit->setText(s);
});
connect(ui->startButton,&QPushButton::clicked,this,[=](){
ui->thread1_Bar->setMaximum(1000);
ui->thread2_Bar->setMaximum(2000);
emit transParam1(1000);
emit transParam2(2000);
QThreadPool::globalInstance()->start(&work[0]);
QThreadPool::globalInstance()->start(&work[1]);
});
}
MainWindow::~MainWindow()
{
delete[] work;
QThreadPool::globalInstance()->waitForDone();
delete ui;
}
void MainWindow::on_startButton_clicked()
{
for(int i=0;i<2;i++){
returnValue[i] = 0;
}
ui->thread1_Bar->setValue(0);
ui->thread1_Edit->setText(0);
ui->thread2_Bar->setValue(0);
ui->thread2_Edit->setText(0);
ui->thread3_Bar->setValue(0);
ui->thread3_Edit->setText(0);
}
执行效果
- 将线程数设为1时,可以看到三个任务依次执行,线程ID唯一
- 将线程数设为3时,可以看到同时执行了两个任务并且使用了两个线程,第三个任务也被分配到了第二个线程里,节省了资源。