一、概述
在一个应用程序中,我们需要多次使用线程,也就意味着,我们需要多次创建并销毁线程。而创建线程并销毁线程的过程势必会消耗内存。QThreadPool是Qt框架中用于管理线程池的类。它提供了一种高效的方式来管理和重用线程,从而减少线程创建和线程的开销。
二、QThreadPool的核心功能
1、线程重用:QThreadPool维护一组线程,任务完成后线程不会被销毁,而是保留在线程池中等待下一个任务。
2、任务队列:当所有线程都在忙碌时,新任务会被放入队列中,等待线程空闲处理。
3、自动扩展和收缩:根据任务数量动态调整线程池中的线程数量。
4、全局线程池:Qt提供了一个全局的QThreadPool实例,可以通过QThreadPool::globalInstance()访问。
三、QThreadPool的主要方法
1、void start(QRunnable *runnable, int priority = 0);
将任务(QRunnable对象)添加到线程池中执行
2、bool tryStart(QRunnable *runnable);
尝试立即执行任务。如果没有可以线程,返回false
3、 bool waitForDone(int msecs = -1);
阻塞当前线程,直到所有任务完成
4、void setMaxThreadCount(int maxThreadCount);
设置线程池最大线程池数
5、 int activeThreadCount() const;
返回当前正执行任务的线程数
6、 static QThreadPool *globalInstance();
返回全局的QThreadPool实例
7、 void setExpiryTimeout(int expiryTimeout);
设置线程池中线程的过期时间(以毫秒为单位),当一个线程在指定时间内没有执行任务时,线程池会将该线程销毁,以减少资源占用。如果为负值(默认),则新创建的线程不会过期,即在线程池销毁之前,线程不会退出。
8、 void clear();
清楚线程池,从队列中移除尚未启动的runnable
四、QRunnable类
QThreadPool的任务是通过QRunnable对象表示的。QRunnable是一个抽象基类,需要继承它并实现run()方法来定义任务的具体逻辑。
1、 virtual void run() = 0;
纯虚函数,子类必须实现。定义任务的具体逻辑
2、 void setAutoDelete(bool _autoDelete) { ref = _autoDelete ? 0 : -1; }
设置任务完成后是否自动删除,默认值为true。这个标志必须在调用QThread::strart()之前设置。在之后调用将出现未定义行为。
3、 bool autoDelete() const { return ref != -1; }
返回任务是否自动删除
五、使用QThreadPool的步骤
1、创建任务:继承QRunnable并实现run()方法
// 自定义任务类
class MyTask : public QRunnable
{
public:
MyTask(int id) : m_id(id) {}
void run() override {
qDebug() << "Task" << m_id << "started in thread" << QThread::currentThreadId();
QThread::sleep(2); // 模拟耗时操作
qDebug() << "Task" << m_id << "finished in thread" << QThread::currentThreadId();
}
private:
int m_id;
};
2、将任务提交到线程池:使用QThreadPool::start()
// 获取全局线程池
QThreadPool* pool = QThreadPool::globalInstance();
// 设置线程池的最大线程数
pool->setMaxThreadCount(3);
// 创建并提交任务
for (int i = 0; i < 10; ++i)
{
MyTask* task = new MyTask(i);
pool->start(task);
}
3、等待任务完成(可选):使用QThreadPool::waitForDone()阻塞当前线程,直到所有任务完成
// 等待所有任务完成
qDebug() << "Waiting for tasks to finish...";
pool->waitForDone();
qDebug() << "All tasks finished!";
六、完整代码
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>
#include <QThread>
// 自定义任务类
class MyTask : public QRunnable
{
public:
MyTask(int id) : m_id(id) {}
void run() override {
qDebug() << "Task" << m_id << "started in thread" << QThread::currentThreadId();
QThread::sleep(2); // 模拟耗时操作
qDebug() << "Task" << m_id << "finished in thread" << QThread::currentThreadId();
}
private:
int m_id;
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
// 获取全局线程池
QThreadPool* pool = QThreadPool::globalInstance();
// 设置线程池的最大线程数
pool->setMaxThreadCount(3);
// 创建并提交任务
for (int i = 0; i < 10; ++i) {
MyTask* task = new MyTask(i);
pool->start(task);
}
// 等待所有任务完成
qDebug() << "Waiting for tasks to finish...";
pool->waitForDone();
qDebug() << "All tasks finished!";
return 0;
}
七、运行结果
Task 0 started in thread 0x1a34
Task 1 started in thread 0x1a38
Task 2 started in thread 0x1a3c
Task 0 finished in thread 0x1a34
Task 3 started in thread 0x1a34
Task 1 finished in thread 0x1a38
Task 4 started in thread 0x1a38
Task 2 finished in thread 0x1a3c
Task 5 started in thread 0x1a3c
...
All tasks finished!
说明:线程池最多同时运行三个任务。当一个任务完成后,线程池会立即从队列中取出下一个任务执行。
八、注意事项
1、任务的生命周期
(1)如果QRunnable的autoDelete()为true(默认值),任务完成后会自动删除。
(2)如果需要在任务完成后手动管理内存,可以将autoDelete()设置为false。
2、线程池的大小
(1)默认情况下,QThreadPool的最大线程数为CPU核心数。
(2)可以通过setMaxThreadCount()调整线程池大小
九、总结
1、QThreadPool是Qt中用于管理线程池的类,适合处理大量短期的任务
2、通过QRunnable定义任务逻辑,并使用QThreadPool提交任务
3、可以设置线程池大小、等待任务完成,并管理任务的生命周期