Qt开发:QtConcurrent介绍和使用

Qt开发:QtConcurrent介绍和使用

文章目录

[一、QtConcurrent 简介](#一、QtConcurrent 简介)

二、常用功能分类

[2.1 异步运行一个函数(无返回值)](#2.1 异步运行一个函数(无返回值))

[2.2 异步运行一个带参数的函数(有返回值)](#2.2 异步运行一个带参数的函数(有返回值))

[2.3 绑定类成员函数](#2.3 绑定类成员函数)

[2.4 容器并行处理(map)](#2.4 容器并行处理(map))

三、线程池控制

四、取消任务

五、典型应用场景

六、完整示例:并发下载图片

一、QtConcurrent 简介

QtConcurrent 是 Qt 提供的一个高级并发编程模块,属于 QtConcurrent 命名空间,旨在简化多线程任务的执行。它支持并行执行算法(如 map、filter、reduce),还支持异步任务运行和结果管理,不需要显式管理 QThread。

模块介绍

头文件包含:

cpp

复制代码

#include

模块依赖:

cpp

复制代码

QT += concurrent

常用功能:

二、常用功能分类

2.1 异步运行一个函数(无返回值)

cpp

复制代码

QtConcurrent::run([]() {

qDebug() << "后台线程中执行任务:" << QThread::currentThread();

});

2.2 异步运行一个带参数的函数(有返回值)

cpp

复制代码

int add(int a, int b) {

return a + b;

}

QFuture future = QtConcurrent::run(add, 3, 5);

// 后续获取结果

int result = future.result(); // 阻塞直到完成

qDebug() << "结果是:" << result;

2.3 绑定类成员函数

cpp

复制代码

class Worker {

public:

int multiply(int x, int y) {

return x * y;

}

};

Worker worker;

QFuture future = QtConcurrent::run(&worker, &Worker::multiply, 4, 6);

2.4 容器并行处理(map)

并发修改容器元素(原地修改)

cpp

复制代码

QList numbers = {1, 2, 3, 4, 5};

auto doubleIt = [](int &n) {

n *= 2;

};

QtConcurrent::map(numbers, doubleIt);

// 输出: 2 4 6 8 10

并发映射容器到新容器(mapped)

cpp

复制代码

QList numbers = {1, 2, 3};

auto square = [](int n) {

return n * n;

};

QList squares = QtConcurrent::mapped(numbers, square).results();

// 输出: 1 4 9

并发过滤(filtered)

cpp

复制代码

QStringList names = {"Alice", "Bob", "Eve"};

auto isShort = [](const QString &name) {

return name.length() <= 3;

};

QStringList shortNames = QtConcurrent::filtered(names, isShort).results();

// 输出: Bob, Eve

2.5 使用 QFutureWatcher 监听结果(推荐与 UI 配合)

cpp

复制代码

QFutureWatcher *watcher = new QFutureWatcher(this);

connect(watcher, &QFutureWatcher::finished, this, [=]() {

QString result = watcher->result();

qDebug() << "计算完成,结果为:" << result;

});

QFuture future = QtConcurrent::run([]() {

QThread::sleep(2);

return QString("Hello from thread");

});

watcher->setFuture(future);

三、线程池控制

QtConcurrent 默认使用全局 QThreadPool,可通过如下方式调整:

cpp

复制代码

QThreadPool::globalInstance()->setMaxThreadCount(8);

或者使用局部线程池:

cpp

复制代码

QThreadPool pool;

QtConcurrent::run(&pool, someFunction);

四、取消任务

可通过 QFuture 中的 cancel() 方法取消任务:

cpp

复制代码

QFuture future = QtConcurrent::run([]{

for (int i = 0; i < 100; ++i) {

if (QThread::currentThread()->isInterruptionRequested()) {

return;

}

QThread::msleep(100);

}

});

// 取消任务

future.cancel();

五、典型应用场景

六、完整示例:并发下载图片

效果目标:

核心类:ImageDownloader

cpp

复制代码

// ImageDownloader.h

#ifndef IMAGEDOWNLOADER_H

#define IMAGEDOWNLOADER_H

#include

#include

#include

#include

class ImageDownloader : public QObject

{

Q_OBJECT

public:

explicit ImageDownloader(QObject *parent = nullptr);

void setMaxConcurrent(int count); // 设置最大并发数

void downloadImages(const QStringList &urls, const QString &saveDir);

signals:

void imageDownloaded(const QString &url, const QString &filePath);

void downloadFailed(const QString &url, const QString &error);

void allFinished();

private:

void downloadOne(const QString &url, const QString &saveDir, int retryCount = 3);

QSemaphore m_semaphore; // 控制并发数

int m_maxConcurrent = 5;

};

#endif // IMAGEDOWNLOADER_H

cpp

复制代码

// ImageDownloader.cpp

#include "ImageDownloader.h"

#include

#include

#include

#include

#include

#include

#include

ImageDownloader::ImageDownloader(QObject *parent)

: QObject(parent), m_semaphore(m_maxConcurrent)

{}

void ImageDownloader::setMaxConcurrent(int count)

{

m_maxConcurrent = count;

m_semaphore = QSemaphore(m_maxConcurrent);

}

void ImageDownloader::downloadImages(const QStringList &urls, const QString &saveDir)

{

for (const QString &url : urls) {

QtConcurrent::run([=]() {

m_semaphore.acquire(); // 限制并发

downloadOne(url, saveDir);

m_semaphore.release();

});

}

// 可选:全部下载完再发信号(略)

}

void ImageDownloader::downloadOne(const QString &urlStr, const QString &saveDir, int retryCount)

{

QNetworkAccessManager manager;

QNetworkRequest request(QUrl(urlStr));

QNetworkReply *reply = manager.get(request);

QEventLoop loop;

QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);

loop.exec();

if (reply->error() == QNetworkReply::NoError) {

QByteArray data = reply->readAll();

QUrl url(urlStr);

QString fileName = QFileInfo(url.path()).fileName();

QString fullPath = QDir(saveDir).filePath(fileName);

QFile file(fullPath);

if (file.open(QIODevice::WriteOnly)) {

file.write(data);

file.close();

emit imageDownloaded(urlStr, fullPath);

} else {

emit downloadFailed(urlStr, "文件保存失败");

}

} else {

if (retryCount > 0) {

qDebug() << "下载失败,重试:" << urlStr;

downloadOne(urlStr, saveDir, retryCount - 1);

} else {

emit downloadFailed(urlStr, reply->errorString());

}

}

reply->deleteLater();

}

使用示例:

cpp

复制代码

ImageDownloader *downloader = new ImageDownloader(this);

downloader->setMaxConcurrent(5); // 最多5张图同时下载

QStringList urls = {

"https://example.com/a.jpg",

"https://example.com/b.jpg",

"https://example.com/c.jpg"

};

QString savePath = QDir::currentPath() + "/images";

connect(downloader, &ImageDownloader::imageDownloaded, this, [](const QString &url, const QString &path){

qDebug() << "下载成功:" << url << " -> " << path;

});

connect(downloader, &ImageDownloader::downloadFailed, this, [](const QString &url, const QString &error){

qWarning() << "下载失败:" << url << error;

});

downloader->downloadImages(urls, savePath);

相关推荐

努比亚是谁旗下的牌子 努比亚品牌介绍【详解】
bat365app官网入口登录

努比亚是谁旗下的牌子 努比亚品牌介绍【详解】

📅 08-30 👁️ 5842
室内设计专业大学排名
365体育APP官网

室内设计专业大学排名

📅 07-17 👁️ 2252
网络安全手势舞:揭秘网络世界的舞蹈艺术
bat365app官网入口登录

网络安全手势舞:揭秘网络世界的舞蹈艺术

📅 08-26 👁️ 9523