目录
前言:使用线程池的场景
第1章 线程池概述
1.1 什么是线程池
1.2 线程池的好处
第2章 QT QThreadPool
2.1 概述
2.2 QRunnable任务对象 =》 可执行的对象
2.3 QThreadPool代码示例
2.5 执行结果演示
(1)需要执行的任务或数据处理是临时性的、执行完就立即空闲,而不是无限制的循环任务
(2)需要执行的任务或数据处理是独立的
(3)需要执行的任务或数据处理的数量是不确定
线程池是一个用于管理和复用多个线程的机制。它由一组预先创建的线程组成,可以在需要时分配任务给这些线程进行执行。
使用线程池可以避免频繁地创建和销毁线程,从而减少线程创建和销毁的开销,并提高程序的性能和效率。
在线程池中,通常包含有限数量的线程,这些线程会在整个应用程序的生命周期内保持活动状态。当有任务需要执行时,线程池会选择一个空闲的线程来接收并执行任务。任务执行完毕后,线程会返回线程池,并等待分配下一个任务,而不是被销毁。
线程池的好处包括:
QThreadPool
2.1 概述
Qt中提供了QThreadPool
类来实现线程池。通过调用QThreadPool
的start()
方法,可以将一个QRunnable
任务对象添加到线程池中进行执行。QThreadPool
会根据设置的最大线程数和任务队列,自动选择合适的线程来执行任务。
使用线程池可以很好地管理多线程任务,提高应用程序的性能和响应性,并减少线程管理的复杂性。同时,还可以通过合理设置线程池的属性,如最大线程数和任务队列大小,来控制线程池的运行方式和资源占用。
在Qt中,可以使用QThreadPool
类来创建和管理线程池,实现多线程任务的分发和执行。线程池可以帮助管理多个线程,并根据需要分配任务,从而提高并发处理能力和资源利用率。
QRunnable
任务对象 =》 可执行的对象在Qt中,QRunnable
是一个基类,用于定义可在线程中执行的任务对象。
通过继承QRunnable
类并实现其run()
函数,可以创建自定义的可执行任务对象。
QRunnable可执行对象,可以被线程池多次调用、执行。
下面是一个简单的示例,展示了如何创建一个自定义的QRunnable
任务对象:
// MyRunnable.h
#ifndef MYRUNNABLE_H
#define MYRUNNABLE_H
#include
#include
class MyRunnable : public QObject, public QRunnable {
Q_OBJECT
public:
explicit MyRunnable(QObject *parent = nullptr);
void run() override;
signals:
void resultReady(int result);
};
// MyRunnable.cpp
#include "MyRunnable.h"
MyRunnable::MyRunnable(QObject *parent)
: QObject(parent)
{
}
//run函数不能是死循环,否则该可执行对象,一旦被执行,就无法结束。
//通常情况下,run函数是可以执行完成,可以被线程池反复执行。
void MyRunnable::run() {
// 执行任务的逻辑
int result = 0;
// ...
// 任务执行完成后,通过发射信号,将结果传递给主线程对象处理
emit resultReady(result);
}
在上述示例中,MyRunnable
类继承自QObject
和QRunnable
。在run()
函数中,可实现具体的任务逻辑。这里只是简单地将result
设为0,你可以根据实际需求编写任务逻辑。
使用QRunnable
的好处是,它提供了一种将任务逻辑与线程解耦的方式。任务逻辑封装在run()
函数中,不需要直接与线程进行交互。任务对象可以在多个线程之间共享和重用,由线程池管理任务的执行。
你可以在主线程或其他工作线程中创建并启动MyRunnable
任务对象。当任务执行完毕后,可以通过发射信号来将执行结果传递给主线程,或者进行其他适当的处理。在主线程中,可以通过连接任务对象的信号来接收执行结果,并在槽函数中处理结果。
注意,当任务对象执行完毕后,请确保将其删除。若使用Qt的线程池(如QThreadPool
)来管理任务对象的生命周期,则线程池会负责在任务执行完毕后销毁任务对象。否则,你需要在任务执行完毕后手动删除任务对象。
QThreadPool代码示例
下面是一个使用Qt线程池的示例:
// MyTask.h
#ifndef MYTASK_H
#define MYTASK_H
#include
#include
class MyTask : public QObject, public QRunnable {
Q_OBJECT
public:
explicit MyTask(QObject *parent = nullptr);
void run() override;
signals:
void resultReady(int result);
};
// MyTask.cpp
#include "MyTask.h"
MyTask::MyTask(QObject *parent)
: QObject(parent)
{
}
void MyTask::run() {
// 执行任务的逻辑
int result = 0;
// ...
count++;
qDebug() << "MyTask is running with "<< QThread::currentThread() ;
//.......
QThread::sleep(3);
qDebug() << "MyTask is done for " << count;
// 发射信号,将结果传递给主线程
qDebug() << "MyTask send singal";
emit resultReady(result);
}
// MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include "MyTask.h"
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void handleTaskResult(int result);
private:
QThreadPool *mThreadPool;
};
#endif // MAINWINDOW_H
// MainWindow.cpp
#include "MainWindow.h"
#include "MyTask.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), mThreadPool(new QThreadPool(this))
{
//创建线程池,并由mThreadPool保存
// 设置线程池的最大线程数,默认为当前系统上可用的最大线程数
mThreadPool->setMaxThreadCount(4);
// 创建并添加任务到线程池中
for (int i = 0; i < 10; ++i)
{
//创建一个runable可执行的对象
MyTask *task = new MyTask(this);
//runable对象执行完成,通过resultReady通知主窗口线程,接收runable对象的执行结果
//因此,连接信号槽
connect(task, &MyTask::resultReady, this, &MainWindow::handleTaskResult);
//把任务添加到线程槽中
mThreadPool->start(task);
}
}
MainWindow::~MainWindow() {
mThreadPool->waitForDone(); // 等待所有任务执行完成
delete mThreadPool;
}
void MainWindow::handleTaskResult(int result) {
// 处理任务执行结果
qDebug() << "Task result:" << result;
}
在上述示例中,MyTask
类是一个自定义任务类,继承自QObject
和QRunnable
。在run
方法中,实现了任务的具体逻辑,并通过发射resultReady
信号将结果传递给主线程。
MainWindow
是一个主线程的类,在构造函数中创建了一个QThreadPool
对象,并设置了最大线程数。然后,创建了10个MyTask
任务,并通过start
方法将它们添加到线程池中进行执行。为了接收任务执行结果,使用connect
函数将任务的resultReady
信号连接到handleTaskResult
槽函数。在槽函数中,可以处理任务的结果。
需要注意的是,在线程池中执行的任务必须派生自QRunnable
类,并实现其run
函数。任务可以通过在run
函数中定义所需的逻辑,并在合适的时机发射信号来传递结果给主线程。
通过使用线程池,可以方便地管理和调度多个任务,充分利用系统资源,提高并发处理能力。可以根据实际需求设置线程池的最大线程数,使其适应当前系统的性能和负载情况。
Main windows is running with QThread(0xab7770)
Runable task is created: 0
Runable task is added into thread pool: 0
Runable task is created: 1
Runable task is added into thread pool: 1
Runable task is created: 2
Runable task is added into thread pool: 2
MyTask is running with QThread(0x30ba4f0, name = "Thread (pooled)")
MyTask is running with QThread(0x30ba400, name = "Thread (pooled)")
Runable task is created: 3
MyTask is running with QThread(0x30b6060, name = "Thread (pooled)")
Runable task is added into thread pool: 3
Runable task is created: 4
MyTask is running with QThread(0x30cd1d0, name = "Thread (pooled)")
Runable task is added into thread pool: 4
Runable task is created: 5
Runable task is added into thread pool: 5
Runable task is created: 6
Runable task is added into thread pool: 6
Runable task is created: 7
Runable task is added into thread pool: 7
Runable task is created: 8
Runable task is added into thread pool: 8
Runable task is created: 9
Runable task is added into thread pool: 9
Main thread started: QThread(0xab7770)
Main thread finished QThread(0xab7770)
MyTask is done for 1
MyTask is done for 1
MyTask is done for 1
MyTask is done for 1
MyTask send singal
MyTask send singal
MyTask send singal
MyTask send singal
Receive Task result: 0
MyTask is running with QThread(0x30cd1d0, name = "Thread (pooled)")
MyTask is running with QThread(0x30b6060, name = "Thread (pooled)")
MyTask is running with QThread(0x30ba400, name = "Thread (pooled)")
MyTask is running with QThread(0x30ba4f0, name = "Thread (pooled)")
Receive Task result: 0
Receive Task result: 0
Receive Task result: 0
MyTask is done for 1
MyTask is done for 1
MyTask is done for 1
MyTask send singal
MyTask is done for 1
MyTask send singal
MyTask send singal
MyTask send singal
MyTask is running with QThread(0x30ba4f0, name = "Thread (pooled)")
Receive Task result: 0
Receive Task result: 0
Receive Task result: 0
MyTask is running with QThread(0x30b6060, name = "Thread (pooled)")
Receive Task result: 0
MyTask is done for 1
MyTask is done for 1
MyTask send singal
MyTask send singal
Receive Task result: 0
Receive Task result: 0