Qt开发:QThreadPool的介绍和使用
文章目录
- 一、QThreadPool 简介
- 二、常用函数简介
- 三、完整示例
一、QThreadPool 简介
QThreadPool 是 Qt 提供的用于高效管理线程资源的类。它通过线程池的方式管理和复用线程,适合处理大量、短时间运行的任务,避免频繁创建和销毁线程带来的性能开销。
常用功能:
- 管理多个可复用的工作线程;
- 接收任务并调度执行;
- 与 QRunnable 配合使用;
- 默认最大线程数为 QThread::idealThreadCount()(通常等于 CPU 核心数);
- 支持设置最大线程数、自定义线程池等。
二、常用函数简介
2.1 int QThreadPool::activeThreadCount() const
功能说明:返回当前线程池中 正在活动(运行任务) 的线程数。
应用场景:
- 实时查看线程池运行状态;
- 调试线程池任务调度情况;
- 控制提交任务的节奏(例如当前线程数未满才继续添加);
- 动态 UI 显示线程使用情况(如进度、资源消耗等)。
示例代码:
#include <QThreadPool>
#include <QDebug>void checkActiveThreads() {QThreadPool *pool = QThreadPool::globalInstance();qDebug() << "当前正在运行的线程数:" << pool->activeThreadCount();
}
结合实际使用:
void addTaskIfIdle() {QThreadPool *pool = QThreadPool::globalInstance();if (pool->activeThreadCount() < pool->maxThreadCount()) {// 当前有空闲线程,可以提交新任务MyTask *task = new MyTask();pool->start(task);qDebug() << "已提交新任务,当前活动线程数:" << pool->activeThreadCount();} else {qDebug() << "线程池已满,稍后再试";}
}
注意事项:
- 线程池是动态调度的,activeThreadCount() 的值可能在多线程环境中随时变化;
- 此函数是 线程安全的(thread-safe),可放心在多线程场景下调用;
- 并不能获取待执行任务数量(可使用 QSemaphore 或自己维护队列实现任务计数)。
2.2 void QThreadPool::clear()
功能说明:
- 从线程池中移除所有等待执行的任务(即任务队列中还未开始运行的任务);
- 不会中断正在执行的任务;
- 被清除的任务如果是 setAutoDelete(true),会自动释放内存。
使用场景:
示例代码:
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>class MyTask : public QRunnable {
public:void run() override {qDebug() << "正在运行任务:" << QThread::currentThread();QThread::sleep(2); // 模拟耗时任务}
};void testClearThreadPool() {QThreadPool *pool = QThreadPool::globalInstance();pool->setMaxThreadCount(2);// 提交5个任务for (int i = 0; i < 5; ++i) {MyTask *task = new MyTask();task->setAutoDelete(true);pool->start(task);}// 清除尚未开始的任务(等待队列中)pool->clear();qDebug() << "已清除未开始执行的任务";
}
注意事项:
- clear() 只影响还没开始运行的任务;
- 正在执行的任务不会被打断;
- 若需要中断正在运行的任务,需要:在任务中定期检查某个取消标志;使用信号控制;或使用 QThread 管理(可中断线程运行);
- 若任务未设置 setAutoDelete(true),被清除后你需要手动 delete。
2.3 int QThreadPool::expiryTimeout() const
作用:返回线程池中线程的“过期超时(expiry timeout)”值,也就是 线程空闲多久后将自动销毁。
应用背景:
- Qt 的线程池会自动回收空闲线程以减少资源消耗;
- expiryTimeout 设置了线程空闲多长时间后自动退出,防止线程常驻内存;
- 如果线程在 timeout 时间内再次有任务进来,线程会被复用;否则会被销毁,任务会由新线程执行。
常见用法:
查看线程池当前过期时间
QThreadPool *pool = QThreadPool::globalInstance();
qDebug() << "线程过期超时设置:" << pool->expiryTimeout() << "毫秒";
示例:动态查看线程池设置
#include <QThreadPool>
#include <QDebug>void checkThreadExpiry() {QThreadPool *pool = QThreadPool::globalInstance();int timeout = pool->expiryTimeout();qDebug() << "当前线程空闲超时时间为:" << timeout << "毫秒";
}
默认值说明:
使用建议:
注意事项:
- 不是任务超时控制! 而是线程空闲后多久自动销毁;
- 如果想设置任务运行超时时间,请自行实现定时器或任务取消逻辑;
- 该值仅影响线程资源生命周期,不影响任务调度本身。
2.4 int QThreadPool::maxThreadCount() const
功能说明:返回当前线程池最多能同时运行的线程数,即线程并发上限。
举例使用:
查看最大线程数
QThreadPool *pool = QThreadPool::globalInstance();
int maxThreads = pool->maxThreadCount();
qDebug() << "最大并发线程数为:" << maxThreads;
示例完整代码:
#include <QThreadPool>
#include <QDebug>void checkMaxThreads() {QThreadPool *pool = QThreadPool::globalInstance();qDebug() << "系统推荐线程数:" << QThread::idealThreadCount();qDebug() << "当前线程池最大线程数:" << pool->maxThreadCount();// 修改最大线程数pool->setMaxThreadCount(6);qDebug() << "新设置的线程数:" << pool->maxThreadCount();
}
注意事项:
- maxThreadCount 并不限制任务数,而是限制同时运行的线程数;
- 超过限制的任务将被排队等待空闲线程;
- 合理设置 maxThreadCount 有助于控制 CPU 占用,避免过载;
2.5 void QThreadPool::releaseThread()
功能说明:手动减少线程池中当前正在使用的线程数量计数(active thread count)。它通常与 reserveThread() 配对使用,用于手动控制线程池中线程资源的分配与释放。
搭配使用函数:
这两个函数并不创建或销毁线程,而是修改线程池的线程调度计数。
使用场景:
- 手动管理线程资源(例如,你希望在线程池外运行一个任务,但仍希望线程池认为资源被占用);
- 结合线程池调度机制实现资源预留、动态控制;
- 防止线程池同时执行过多重量级任务。
示例:手动预留和释放线程数
#include <QThreadPool>
#include <QDebug>void manualThreadReservationExample() {QThreadPool *pool = QThreadPool::globalInstance();qDebug() << "初始最大线程数:" << pool->maxThreadCount();qDebug() << "当前活动线程数:" << pool->activeThreadCount();// 预留两个线程名额pool->reserveThread();pool->reserveThread();qDebug() << "预留2个线程后,可用线程减少";// 此时任务提交将受到最大线程数 - 预留数量的限制// 执行完后释放线程名额pool->releaseThread();pool->releaseThread();qDebug() << "已释放预留线程,线程池恢复可用资源";
}
注意事项:
- 不要调用 releaseThread() 多于 reserveThread() 次数,否则行为未定义;
- 不影响正在运行的线程,仅影响调度器的内部计数;
- 使用前确保了解线程池任务调度原理,避免死锁或资源错误判断;
- 若使用不当可能会导致线程池任务无法调度或调度过多。
2.6 void QThreadPool::setExpiryTimeout(int expiryTimeout)
参数说明:expiryTimeout:以毫秒为单位,指定一个线程在空闲多久后将被销毁(退出)。如果设置为 -1,表示线程永远不会因空闲而销毁。默认值是 30000 毫秒(30 秒)。
作用:这个函数用于优化线程资源使用,当线程池中的线程空闲超过指定时间,它们将被自动销毁,从而释放系统资源。
使用示例:
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Task running on thread:" << QThread::currentThread();QThread::sleep(1);}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool* pool = QThreadPool::globalInstance();// 设置空闲线程在 5 秒后自动销毁pool->setExpiryTimeout(5000);// 提交一个任务pool->start(new MyTask());// 等待所有任务完成pool->waitForDone();qDebug() << "All tasks done. Wait to see if thread exits.";// 等待超过 5 秒,以观察线程是否被销毁QThread::sleep(7);return 0;
}
2.7 void QThreadPool::setMaxThreadCount(int maxThreadCount)
参数说明:maxThreadCount:线程池中允许同时活动的线程最大数量(非等待任务数量)。必须大于 0,否则不会生效。默认值通常为系统核心数:QThread::idealThreadCount()。
作用说明:
setMaxThreadCount() 控制了线程池的并发程度:
- 如果你提交了很多任务,线程池也只会最多并发执行 maxThreadCount 个任务,其他任务会排队。
- 增加 maxThreadCount 可以提升并发处理能力,但也会增加线程上下文切换、CPU 竞争。
使用示例:
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Running task on thread:" << QThread::currentThread();QThread::sleep(2); // 模拟耗时任务}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool* pool = QThreadPool::globalInstance();// 设置最大线程数为 2(并发数限制为 2)pool->setMaxThreadCount(2);qDebug() << "Max thread count:" << pool->maxThreadCount();// 提交 5 个任务for (int i = 0; i < 5; ++i) {pool->start(new MyTask());}pool->waitForDone();qDebug() << "All tasks completed.";return 0;
}
输出分析(示意):
Max thread count: 2
Running task on thread: 0x7ff...
Running task on thread: 0x7ff...
... 2 秒后 ...
Running task on thread: 0x7ff...
Running task on thread: 0x7ff...
... 再 2 秒 ...
Running task on thread: 0x7ff...
可以看到虽然提交了 5 个任务,但同时运行的最多只有 2 个线程。
2.8 void QThreadPool::setStackSize(uint stackSize)
参数说明:
- stackSize:单位是字节(byte),表示线程的栈大小。
- 通常应设置为足够执行任务所需的内存空间。
- 如果设置为 0,表示使用系统默认栈大小。
- 如果设置值太小,可能会导致线程运行时栈溢出(stack overflow)。
- 设置过大,则会增加内存占用。
作用与适用场景:
注意:不是所有平台都支持修改线程栈大小,在某些平台(如 Windows)上无效或有限制。
使用示例:
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Task running. Thread:" << QThread::currentThread();char largeArray[1024 * 512]; // 使用较大的局部变量,512 KBlargeArray[0] = 1; // 防止优化}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool* pool = QThreadPool::globalInstance();// 设置每个线程栈大小为 2 MBpool->setStackSize(2 * 1024 * 1024);qDebug() << "Set thread stack size to 2MB";pool->start(new MyTask());pool->waitForDone();return 0;
}
注意事项:
- 只对新创建的线程生效,对已存在的线程无效。
- 与操作系统有关,某些系统可能会忽略此设置或限制最大栈大小。
- 设置过小容易造成崩溃(stack overflow),尤其在递归或大数组情况下。
- 大部分任务无需设置栈大小,仅在特殊需求下使用。
2.9 uint QThreadPool::stackSize() const
返回值:
- 返回一个 uint(无符号整数),表示线程池中新创建线程的栈大小(单位:字节)。
- 如果返回值为 0,表示使用系统默认的线程栈大小。
作用说明:查询你通过 setStackSize() 设置的栈大小配置值。它不会告诉你系统默认的实际栈大小,只会返回你自己设定的值或 0。
使用示例:
#include <QCoreApplication>
#include <QThreadPool>
#include <QDebug>int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool *pool = QThreadPool::globalInstance();// 设置栈大小为 1 MBpool->setStackSize(1024 * 1024);// 读取当前设置的栈大小uint size = pool->stackSize();qDebug() << "Current thread stack size:" << size << "bytes";return 0;
}
输出示例:
Current thread stack size: 1048576 bytes
如果你没有调用 setStackSize(),默认输出为:
Current thread stack size: 0 bytes
2.10 void QThreadPool::start(QRunnable *runnable, int priority = 0)
参数说明:
- runnable:指向一个继承自 QRunnable 的任务对象指针。
- priority:任务优先级(整型),默认值为 0。
- 数值越大,优先级越高。
- 是相对优先级,不代表线程调度的精确控制,仅用于线程池内部排序。
- 通常范围在 -128 ~ 127(没有硬性限制,但这个区间最常用)。
使用示例:
示例:提交一个任务到线程池
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Running task in thread:" << QThread::currentThread();}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 获取全局线程池QThreadPool* pool = QThreadPool::globalInstance();// 创建任务QRunnable* task = new MyTask();task->setAutoDelete(true); // 任务完成后自动释放内存// 提交任务,优先级为默认(0)pool->start(task);pool->waitForDone(); // 等待所有任务执行完毕return 0;
}
示例:带优先级任务
QRunnable* low = new MyTask();
QRunnable* high = new MyTask();low->setAutoDelete(true);
high->setAutoDelete(true);// 高优先级任务先执行
pool->start(high, 10);
pool->start(low, -5);
2.11 bool QThreadPool::tryStart(QRunnable *runnable)
参数说明:runnable:指向 QRunnable 子类的任务对象。
功能说明:用于尝试立即启动一个任务,如果线程池中当前有空闲线程可用,就立即执行,否则不执行任务。
返回值:
- true:任务已被成功启动(线程池中有空闲线程)。
- false:线程池中没有空闲线程,任务未启动,你需要手动处理(例如等待或丢弃)。
作用说明:
使用示例:
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Running task in thread:" << QThread::currentThread();QThread::sleep(2); // 模拟耗时任务}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool *pool = QThreadPool::globalInstance();pool->setMaxThreadCount(2); // 最多两个并发线程// 启动两个任务,占满线程池pool->start(new MyTask());pool->start(new MyTask());// 第三个任务尝试用 tryStart 启动(可能失败)QRunnable *extra = new MyTask();extra->setAutoDelete(true);if (pool->tryStart(extra)) {qDebug() << "Extra task started.";} else {qDebug() << "No threads available — task not started.";delete extra; // 必须手动释放,否则内存泄漏}pool->waitForDone();return 0;
}
注意事项:
2.12 bool QThreadPool::tryTake(QRunnable *runnable)
参数说明:runnable:指向你先前提交(但尚未开始执行)的 QRunnable 任务对象。
返回值:
- true:任务成功被从线程池队列中移除(即:尚未开始执行,已经成功取消)。
- false:任务已经开始执行或不在队列中,无法移除。
作用说明:
- 任务撤销:在任务还没开始前取消它。
- 动态调整任务:根据程序逻辑变化取消一些不再需要的任务。
使用示例:
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>
#include <QThread>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Task running in thread:" << QThread::currentThread();QThread::sleep(2);}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool* pool = QThreadPool::globalInstance();pool->setMaxThreadCount(1); // 限制只允许一个线程运行// 创建两个任务MyTask* task1 = new MyTask();task1->setAutoDelete(true);MyTask* task2 = new MyTask();task2->setAutoDelete(true);pool->start(task1); // 会立即执行(占用线程)pool->start(task2); // 会排队// 尝试移除 task2(注意它必须尚未运行)bool removed = pool->tryTake(task2);qDebug() << (removed ? "Task2 was removed from queue" : "Task2 could not be removed");pool->waitForDone();return 0;
}
输出示例:
Task running in thread: 0x7f8c4bc0
Task2 was removed from queue
2.13 bool QThreadPool::waitForDone(int msecs = -1)
参数说明:
- msecs:等待的最长时间(单位:毫秒)。
- 默认值 -1 表示无限等待,直到所有任务执行完毕为止。
- 设为具体时间值(如 5000)表示最多等待 5 秒。
返回值:
- true:所有任务已完成。
- false:等待超时,还有任务未完成。
作用说明:这个函数主要用于在程序需要确保所有任务执行完毕再继续下一步操作时使用。
使用示例:
示例:无限等待所有任务执行完毕
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>
#include <QThread>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Task started in thread:" << QThread::currentThread();QThread::sleep(2); // 模拟耗时任务qDebug() << "Task finished";}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool *pool = QThreadPool::globalInstance();for (int i = 0; i < 3; ++i) {MyTask *task = new MyTask();task->setAutoDelete(true);pool->start(task);}qDebug() << "Waiting for tasks to finish...";pool->waitForDone(); // 等待所有任务完成qDebug() << "All tasks completed.";return 0;
}
示例:最多等待 3 秒
bool success = pool->waitForDone(3000); // 最多等待 3000ms
if (success) {qDebug() << "Tasks finished in time.";
} else {qDebug() << "Timeout! Tasks still running.";
}
三、完整示例
示例功能:
- 使用 QThreadPool 提交多个任务;
- 每个任务继承自 QRunnable 并在子线程中执行;
- 控制台打印线程运行情况;
- 可自由设置线程池线程数。
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QThread>
#include <QDebug>// 自定义任务类,继承 QRunnable
class MyTask : public QRunnable {
public:MyTask(int id) : taskId(id) {setAutoDelete(true); // 任务执行后自动释放内存}void run() override {qDebug() << "任务开始 ID:" << taskId<< "在线程:" << QThread::currentThread();QThread::sleep(2); // 模拟耗时操作qDebug() << "任务完成 ID:" << taskId;}private:int taskId;
};int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);QThreadPool *pool = QThreadPool::globalInstance();// 设置最大线程数(可选)pool->setMaxThreadCount(4);qDebug() << "线程池最大线程数:" << pool->maxThreadCount();// 提交多个任务for (int i = 0; i < 8; ++i) {MyTask *task = new MyTask(i);pool->start(task);}// 等待所有任务完成pool->waitForDone();qDebug() << "所有任务已完成";return 0;
}
输出结果:
线程池最大线程数: 4
任务开始 ID: 0 在线程: QThread(0x2e436e0, name = "Thread (pooled)")
任务开始 ID: 1 在线程: QThread(0x2e43710, name = "Thread (pooled)")
任务开始 ID: 2 在线程: QThread(0x2e43b90, name = "Thread (pooled)")
任务开始 ID: 3 在线程: QThread(0x2e43aa0, name = "Thread (pooled)")
任务完成 ID: 2
任务完成 ID: 3
任务完成 ID: 0
任务完成 ID: 1
任务开始 ID: 4 在线程: QThread(0x2e43b90, name = "Thread (pooled)")
任务开始 ID: 5 在线程: QThread(0x2e43aa0, name = "Thread (pooled)")
任务开始 ID: 6 在线程: QThread(0x2e436e0, name = "Thread (pooled)")
任务开始 ID: 7 在线程: QThread(0x2e43710, name = "Thread (pooled)")
任务完成 ID: 4
任务完成 ID: 6
任务完成 ID: 7
任务完成 ID: 5
所有任务已完成
关键知识点总结