3. 使用QThreadPool执行任务

使用QThreadPool执行任务 学习卡片

任务目标

本案例演示如何通过QRunnable与QThreadPool在Qt中执行并发任务。你将创建一个继承自QRunnable的任务类,重写其run()方法,并使用QThreadPool::start()提交多个任务到线程池执行,从而避免为每个短任务单独创建线程的开销。

环境依赖

需要Qt 5.10或更高版本(使用QThreadPool::start(QRunnable*, int priority)重载),以及支持C++11的编译器。在项目文件(.pro)中确保包含:

QT += core
CONFIG += c++11

关键完整代码

以下代码创建了一个简单的QRunnable子类,每个任务输出其编号与执行线程ID,并在main()中通过线程池提交8个任务:

#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QThread>
#include <QDebug>

class Task : public QRunnable {
public:
    explicit Task(int id) : m_id(id) {
        // 任务执行完毕后自动删除该对象
        setAutoDelete(true);
    }

    void run() override {
        qInfo() << "任务" << m_id << "开始于线程:"
               << QThread::currentThreadId();
        // 模拟耗时操作
        QThread::msleep(50);
        qInfo() << "任务" << m_id << "结束于线程:"
               << QThread::currentThreadId();
    }

private:
    int m_id;
};

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    QThreadPool *pool = QThreadPool::globalInstance();
    qInfo() << "最大线程数:" << pool->maxThreadCount();

    // 提交8个任务到全局线程池
    for (int i = 1; i <= 8; ++i) {
        Task *task = new Task(i);
        pool->start(task);
    }

    // 等待所有任务完成(阻塞直到队列清空)
    pool->waitForDone();
    qInfo() << "所有任务已完成";

    return 0;
}

运行与验证

编译运行:

qmake
make
./threadpool_demo

验证方法:程序启动后,观察控制台输出。预期看到8个任务均被执行,且每个任务输出其开始与结束的线程ID。由于线程池默认最大线程数通常等于CPU核心数,多个任务会并发运行在不同线程上,因此不同任务的线程ID可能相同(当任务数大于线程数时,后续任务会等待空闲线程)。

通过条件:所有8个任务均打印了“开始”与“结束”日志,且程序在打印“所有任务已完成”后正常退出,无崩溃或死锁。

关键说明

  • setAutoDelete(true)使线程池在任务执行完毕后自动删除Task对象,因此使用new创建任务后无需手动管理内存。
  • waitForDone()阻塞主线程直到所有已提交任务执行完毕,确保主线程退出前任务全部完成。
  • 若需限制并发数,可通过pool->setMaxThreadCount(n)设置;本例使用全局线程池默认配置。