Qt QtConcurrent使用入门浅解

QtConcurrent 是 Qt 提供的​​高级并发编程框架​ ​,旨在简化多线程开发------无需手动管理线程生命周期,通过封装线程池(QThreadPool)和高阶函数(如 map/filter/reduce),快速实现异步任务、容器处理和结果监控。

一、为什么选择 QtConcurrent?

相比底层线程(QThread/pthread),QtConcurrent 的优势:

  • ​自动线程管理​​:基于全局/自定义线程池,避免频繁创建/销毁线程的开销;

  • ​高阶抽象​ ​:通过 QtConcurrent::run/map/filter等函数,直接处理任务逻辑,无需关心线程调度;

  • ​结果与进度监控​ ​:通过 QFutureQFutureWatcher轻松获取异步结果、监听进度和取消任务;

  • ​线程安全简化​​:内置对共享资源的保护(需配合锁机制)。

二、核心组件

QtConcurrent 的核心是 ​QFuture ​(异步结果句柄)和 ​QFutureWatcher​(结果监控器),以及命名空间内的高阶函数。

1. QFuture:异步操作的"结果包裹器"

  • 代表一个​​异步操作的结果​​,可通过它获取返回值、进度、取消状态;

  • 常用方法:

    • result():阻塞获取最终结果(需谨慎,避免 UI 卡顿);

    • resultAt(int index):获取容器处理任务中的单个元素结果(如 map后的元素);

    • progress()/progressRange():获取/设置进度范围;

    • isFinished()/isCanceled():判断任务状态;

    • waitForFinished():阻塞等待任务完成。

2. QFutureWatcher:结果的"观察者"

  • 继承自 QObject,通过信号监控 QFuture的状态变化:

    • finished():任务完成;

    • canceled():任务取消;

    • progressChanged(int):进度更新;

    • resultReadyAt(int):容器处理任务中某个元素的结果就绪;

    • resultReady(QVariant):单个结果就绪(部分场景)。

3. 高阶函数(命名空间 QtConcurrent

QtConcurrent 提供了一系列模板函数,直接处理任务逻辑:

函数 功能 示例
QtConcurrent::run 运行一个函数,返回 QFuture run(myFunction, arg1, arg2)
QtConcurrent::map 对容器​​每个元素​​应用函数 map(list, toUpper)
QtConcurrent::filter 过滤容器中​​满足条件的元素​ filter(list, isEven)
QtConcurrent::reduce 合并容器元素(类似 MapReduce 的 Reduce) reduce(list, sum)

三、基础用法详解

1. 用 QtConcurrent::run运行耗时函数

​场景​​:后台执行一个不阻塞 UI 的耗时操作(如计算、IO)。

步骤:
  • ​定义耗时函数​ ​:可返回值,也可通过 QFutureInterface报告进度/取消。

  • ​启动任务​ ​:用 QtConcurrent::run运行函数,获取 QFuture

  • ​监控任务​ ​:用 QFutureWatcher监听结果/进度/取消。

​示例代码​​:

cpp 复制代码
#include <QtConcurrent/QtConcurrent>
#include <QFutureWatcher>
#include <QDebug>

// 耗时函数:模拟计算,支持进度报告和取消
int longRunningTask(int base) 
{
    QFutureInterface<int> futureInterface;
    futureInterface.setProgressRange(0, 100); // 进度范围 0~100
    futureInterface.reportStarted();          // 报告任务开始

    for (int i = 0; i < 100; ++i) {
        if (futureInterface.isCanceled()) {   // 检查是否被取消
            qDebug() << "Task canceled!";
            return -1;
        }
        QThread::msleep(50);                  // 模拟工作
        futureInterface.setProgress(i);       // 更新进度
    }

    futureInterface.reportFinished();         // 报告任务结束
    return base * 2;                          // 返回结果
}

// 在 UI 槽函数中启动任务
void MyWidget::onStartTask() 
{
    QFuture<int> future = QtConcurrent::run(longRunningTask, 10); // 传递参数 10
    QFutureWatcher<int>* watcher = new QFutureWatcher<int>(this);

    // 监听进度变化
    connect(watcher, &QFutureWatcher<int>::progressChanged, this, [=](int progress) {
        qDebug() << "Progress:" << progress << "%";
        ui->progressBar->setValue(progress); // 更新 UI 进度条
    });

    // 监听任务完成
    connect(watcher, &QFutureWatcher<int>::finished, this, [=]() {
        qDebug() << "Result:" << watcher->result(); // 输出 20
        watcher->deleteLater(); // 清理资源
    });

    watcher->setFuture(future); // 关联 QFuture 和 watcher
}

​关键点​​:

  • 函数内部通过 QFutureInterface报告进度和取消状态;

  • QFutureWatcher监听进度变化,实时更新 UI;

  • 任务取消时,函数通过 isCanceled()退出,避免无效计算。

2. 用 QtConcurrent::map处理容器

​场景​ ​:对容器(如 QList/QVector)中的每个元素执行相同操作(如字符串转大写、图像缩放)。

示例代码:
复制代码
#include <QtConcurrent/QtConcurrent>
#include <QFutureWatcher>
#include <QList>
#include <QString>
#include <QDebug>

// 转换函数:字符串转大写
QString toUpper(const QString& str) {
    return str.toUpper();
}

// 启动 map 任务
void MyWidget::onMapStrings() {
    QList<QString> strings = {"hello", "world", "qt", "concurrent"};
    QFuture<QString> future = QtConcurrent::map(strings, toUpper); // 对每个元素应用 toUpper

    QFutureWatcher<QString>* watcher = new QFutureWatcher<QString>(this);

    // 监听单个元素结果就绪(处理一个元素就触发一次)
    connect(watcher, &QFutureWatcher<QString>::resultReadyAt, this, [=](int index) {
        QString result = watcher->resultAt(index); // 获取该元素的结果
        qDebug() << "Processed index" << index << ":" << result;
    });

    // 监听所有元素处理完成
    connect(watcher, &QFutureWatcher<QString>::finished, this, [=]() {
        qDebug() << "All results:" << future.results(); // 获取所有结果(QList<QString>)
        watcher->deleteLater();
    });

    watcher->setFuture(future);
}

​关键点​​:

  • map自动将容器元素分发给线程池中的线程处理;

  • resultReadyAt信号在​​每个元素处理完​​时触发,可实时更新 UI;

  • results()返回处理后的完整容器。

3. 用 QtConcurrent::filter过滤容器

​场景​​:从容器中筛选满足条件的元素(如筛选偶数、过滤错误日志)。

示例代码:
复制代码
#include <QtConcurrent/QtConcurrent>
#include <QFutureWatcher>
#include <QList>
#include <QDebug>

// 谓词函数:判断是否为偶数
bool isEven(int num) {
    return num % 2 == 0;
}

// 启动 filter 任务
void MyWidget::onFilterNumbers() {
    QList<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    QFuture<int> future = QtConcurrent::filter(numbers, isEven); // 过滤偶数

    QFutureWatcher<int>* watcher = new QFutureWatcher<int>(this);

    connect(watcher, &QFutureWatcher<int>::resultReadyAt, this, [=](int index) {
        qDebug() << "Filtered element:" << watcher->resultAt(index);
    });

    connect(watcher, &QFutureWatcher<int>::finished, this, [=]() {
        qDebug() << "Filtered results:" << future.results(); // 输出 {2,4,6,8,10}
        watcher->deleteLater();
    });

    watcher->setFuture(future);
}

4. 用 QtConcurrent::reduce合并结果

​场景​​:合并容器元素(如求和、求最大值),类似 MapReduce 的 Reduce 阶段。

示例代码:
复制代码
#include <QtConcurrent/QtConcurrent>
#include <QFutureWatcher>
#include <QList>
#include <QDebug>

// Reduce 函数:两数相加
int sum(int a, int b) {
    return a + b;
}

// 启动 reduce 任务
void MyWidget::onSumNumbers() {
    QList<int> numbers = {1, 2, 3, 4, 5};
    QFuture<int> future = QtConcurrent::reduce(numbers, sum); // 计算总和

    QFutureWatcher<int>* watcher = new QFutureWatcher<int>(this);
    connect(watcher, &QFutureWatcher<int>::finished, this, [=]() {
        qDebug() << "Sum:" << watcher->result(); // 输出 15
        watcher->deleteLater();
    });

    watcher->setFuture(future);
}

​关键点​​:

  • reduce将容器分成多个块,每个线程处理一块,再将块结果合并;

  • Reduce 函数需满足​​结合律​​(如加法、乘法),否则结果不确定。

四、线程池配置

QtConcurrent 基于 QThreadPool管理线程,默认使用​​全局线程池​​。可根据硬件资源调整线程数(如 ZynqMP 的 A53 核心数):

cpp 复制代码
#include <QThreadPool>

// 获取全局线程池
QThreadPool* globalPool = QThreadPool::globalInstance();
globalPool->setMaxThreadCount(4); // 设置最大线程数为 4(匹配 ZynqMP 的 4 个 A53 核心)
globalPool->setExpiryTimeout(30000); // 线程空闲 30 秒后销毁,避免资源浪费

// 使用自定义线程池
QThreadPool* customPool = new QThreadPool(this);
customPool->setMaxThreadCount(2);
QFuture<int> future = QtConcurrent::run(customPool, longRunningTask, 10); // 指定线程池运行任务

五、嵌入式场景实践

以​​视频帧缩放​​为例,展示 QtConcurrent 在嵌入式设备中的应用:

场景需求

从摄像头获取视频帧(QImage),需缩放至 640x480 显示,要求不阻塞 UI 线程。

实现步骤:

  1. ​定义缩放函数​​:处理单帧图像;

  2. ​用 map并行处理帧列表​​;

  3. ​监控进度,实时更新 UI​​。

代码实现:
复制代码
// 缩放函数:将帧缩放到指定尺寸
QImage scaleFrame(const QImage& frame, const QSize& targetSize) {
    if (frame.isNull()) return QImage();
    return frame.scaled(targetSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}

// 视频处理槽函数:接收原始帧列表
void VideoProcessor::processFrameBatch(const QList<QImage>& rawFrames) {
    // 目标尺寸:适配监视器 UI
    QSize targetSize(640, 480);
    
    // 启动 map 任务:并行缩放所有帧
    QFuture<QImage> future = QtConcurrent::map(rawFrames, [=](const QImage& frame) {
        return scaleFrame(frame, targetSize);
    });

    // 创建 watcher 监控任务
    QFutureWatcher<QImage>* watcher = new QFutureWatcher<QImage>(this);
    
    // 单帧结果就绪:更新 UI 中的对应帧
    connect(watcher, &QFutureWatcher<QImage>::resultReadyAt, this, [=](int index) {
        QImage scaledFrame = watcher->resultAt(index);
        emit frameScaled(index, scaledFrame); // 发射信号,UI 组件接收并显示
    });

    // 所有帧处理完成:清理资源
    connect(watcher, &QFutureWatcher<QImage>::finished, this, [=]() {
        qDebug() << "Batch scaling finished!";
        watcher->deleteLater();
    });

    watcher->setFuture(future);
}

​优势​​:

  • 并行处理多帧,充分利用 ZynqMP 的多核 CPU;

  • 不阻塞 UI 线程,保证监视器实时响应;

  • 单帧结果就绪后立即更新 UI,提升用户体验。

六、注意事项

  1. ​线程安全​ ​:函数内部访问共享资源(如全局变量、硬件寄存器)时,需用 QMutex加锁;

  2. ​异常处理​ ​:函数抛出的异常会被捕获并存储在 QFuture中,调用 result()时需 try-catch

  3. ​取消任务​ ​:长时间任务需定期检查 isCanceled(),避免无效计算;

  4. ​内存管理​ ​:QFutureWatcher需手动释放(deleteLater()),避免内存泄漏;

  5. ​性能优化​​:根据任务类型调整线程池大小(如计算密集型任务设为核心数,IO 密集型可适当增大)。

总结

QtConcurrent 是 Qt 并发编程的"瑞士军刀",通过高阶函数和简洁的 API,快速实现异步任务、容器处理和结果监控。在 ZynqMP 等嵌入式平台中,合理使用 QtConcurrent 可充分发挥多核 CPU 性能,提升应用的响应性和实时性。

如需深入,可参考 Qt 官方文档:Qt Concurrent Module

惠州大亚湾

相关推荐
我是华为OD~HR~栗栗呀4 小时前
23届考研-Java面经(华为OD)
java·c++·python·华为od·华为·面试
爱吃喵的鲤鱼4 小时前
仿mudou——Connection模块(连接管理)
linux·运维·服务器·开发语言·网络·c++
郝学胜-神的一滴4 小时前
使用Linux的read和write系统函数操作文件
linux·服务器·开发语言·数据库·c++·程序人生·软件工程
2301_803554525 小时前
C++联合体(Union)详解:与结构体的区别、联系与深度解析
java·c++·算法
pu_taoc5 小时前
深入剖析:基于epoll与主从Reactor模型的高性能服务器设计与实现
服务器·c语言·c++·vscode
初圣魔门首席弟子5 小时前
c++ bug 函数定义和声明不一致导致出bug
开发语言·c++·bug
bkspiderx6 小时前
C++设计模式之行为型模式:中介者模式(Mediator)
c++·设计模式·中介者模式
敢敢J的憨憨L6 小时前
GPTL(General Purpose Timing Library)使用教程
java·服务器·前端·c++·轻量级计时工具库
小欣加油6 小时前
leetcode 62 不同路径
c++·算法·leetcode·职场和发展