3. 使用QtConcurrent::run执行异步任务

使用QtConcurrent::run执行异步任务 学习卡片

任务目标

使用 QtConcurrent::run 将一个计算密集型函数提交到后台线程池执行,主线程保持响应;通过返回的 QFuture 对象获取异步任务的结果,并验证任务确实在非 GUI 线程中运行。

环境与依赖

  • Qt 5.10+ 或 Qt 6(含 Concurrent 模块)
  • 项目文件 .pro 中添加:QT += concurrent
  • 编译器需支持 C++11 或更高版本

关键完整代码

// main.cpp
#include <QCoreApplication>
#include <QtConcurrent>
#include <QFuture>
#include <QThread>
#include <QDebug>

// 后台执行的耗时函数:计算从 1 到 n 的累加和
int sumUpTo(int n) {
    qInfo() << "任务运行线程:" << QThread::currentThread();
    int sum = 0;
    for (int i = 1; i <= n; ++i) {
        sum += i;
        // 模拟耗时操作
        QThread::msleep(2);
    }
    return sum;
}

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

    qInfo() << "主线程:" << QThread::currentThread();

    // 提交异步任务,返回 QFuture 用于获取结果
    QFuture<int> future = QtConcurrent::run(sumUpTo, 100);

    // 主线程不被阻塞,可继续执行其他操作
    qInfo() << "任务已提交,主线程继续执行...";

    // 等待任务完成并获取结果
    future.waitForFinished();
    int result = future.result();

    qInfo() << "计算结果:" << result;

    return 0;
}

运行与验证

  1. 创建 Qt 控制台项目,将上述代码保存为 main.cpp,在 .pro 文件中添加 QT += concurrent。
  2. 编译并运行程序。
  3. 通过条件:程序输出中“任务运行线程”的线程地址与“主线程”的线程地址不同,且最终输出“计算结果: 5050”(1 到 100 的累加和)。

预期输出(示例)

主线程: QThread(0x...)
任务已提交,主线程继续执行...
任务运行线程: QThread(0x...)
计算结果: 5050

其中两行线程地址不同,即证明 sumUpTo 在后台线程池线程中执行,而非主线程。

关键说明

  • QtConcurrent::run 默认使用全局线程池,无需手动创建 QThread 对象。
  • future.waitForFinished() 会阻塞当前线程直到任务完成;若不想阻塞,可改用 QFutureWatcher 的信号槽机制,但本案例为最小闭环,直接阻塞等待结果。
  • 若函数需要多个参数,直接在 run 中依次传入即可,例如 QtConcurrent::run(func, arg1, arg2)。