Qt多线程之QtConcurrent
Qt多线程之QtConcurrent
目录
箴言:
《山居秋暝》 — 王维
空山新雨后,天气晚来秋。
明月松间照,清泉石上流。
竹喧归浣女,莲动下渔舟。
随意春芳歇,王孙自可留。

介绍
在 Qt 中,多线程编程是提高应用性能、避免 GUI 阻塞的常用手段。传统方式是继承 QThread,管理线程启动、同步、销毁,但管理复杂、易出错。
QtConcurrent 提供了一个更高级的接口,让我们可以轻松启动并行任务,而无需手动管理线程。本文将从功能、用法到实际案例,带你全面了解 QtConcurrent。
QtConcurrent 是 Qt 提供的 高层次并行编程模块:
- 允许在后台线程执行函数或任务
- 自动使用线程池管理线程
- 提供并行算法(map、filter、reduce)
- 支持任务结果的
QFuture和QFutureWatcher,便于异步获取结果
特点:高效、简洁、易用、无需手动管理 QThread
1. 基础用法
1.1 QtConcurrent::run
将一个函数或成员函数 放到后台线程运行,自动使用线程池,无需自己管理 QThread。默认是异步的。
同步阻塞调用:
int heavyComputation(int a, int b)
{
QThread::sleep(2);
qDebug() << quint64(QThread::currentThreadId());
return a + b;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "主线程: " << quint64(QThread::currentThreadId());
QFuture<int> future = QtConcurrent::run(heavyComputation, 1, 2);
qDebug() << future.result();
qDebug() << "Exit...";
return a.exec();
}
主线程: 5340
21520
3
Exit...
异步调用:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "主线程: " << quint64(QThread::currentThreadId());
QFuture<int> future = QtConcurrent::run(heavyComputation, 1, 2);
QFutureWatcher<int>* watcher = new QFutureWatcher<int>();
QObject::connect(watcher, &QFutureWatcher<int>::finished, &a, [watcher]()
{
qDebug() << "Result: " << watcher->future().result();
watcher->deleteLater();
});
watcher->setFuture(future);
qDebug() << "Exit...";
return a.exec();
}
主线程: 20092
Exit...
5956
Result: 3
1.2 QtConcurrent::map
- 修改原容器
- 返回
QFuture<void>
同步阻塞调用,每一次调用 容器中的元素,都是不同的线程。
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "主线程: " << quint64(QThread::currentThreadId());
QVector<int> data = {1,2,3,4};
QFuture<void> future = QtConcurrent::map(data, [](int &v)
{
QThread::msleep(100);
v *= 2;
qDebug() << v << quint64(QThread::currentThreadId());
});
future.waitForFinished();
qDebug() << "Exit...";
return a.exec();
}
主线程: 16316
4 18404
6 8872
2 4620
8 14440
Exit...
异步调用
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "主线程: " << quint64(QThread::currentThreadId());
QVector<int> data = {1,2,3,4};
QFuture<void> future = QtConcurrent::map(data, [](int &v)
{
QThread::msleep(100);
v *= 2;
qDebug() << v << quint64(QThread::currentThreadId());
});
QFutureWatcher<void>* watcher = new QFutureWatcher<void>();
QObject::connect(watcher, &QFutureWatcher<void>::finished, [&data, watcher]{
qDebug() << "Done:" << data << quint64(QThread::currentThreadId());
watcher->deleteLater();
});
watcher->setFuture(future);
qDebug() << "Exit...";
return a.exec();
}
主线程: 10308
Exit...
4 14824
6 19868
8 10136
2 21612
Done: QVector(2, 4, 6, 8) 10308
1.3 QtConcurrent::mapped + QFuture
不修改原数据 + 返回新结果 + 返回 QFuture<T>
注意,在mapped中的函数对象不能是 Lambda,在Qt5.12.8 版本无法推导类型。
QString mapFunc(int v)
{
QThread::msleep(100);
return QString("++ %1 ++ %2").arg(v).arg(quint64(QThread::currentThreadId()));
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "主线程: " << quint64(QThread::currentThreadId());
QVector<int> data = {1,2,3,4};
QFuture<QString> future = QtConcurrent::mapped(data, mapFunc);
future.waitForFinished();
QList<QString> result = future.results();
qDebug() << "Exit..." << result;
return a.exec();
}
主线程: 12428
Exit... ("++ 1 ++ 21636", "++ 2 ++ 11032", "++ 3 ++ 4496", "++ 4 ++ 20696")
异步调用版本
QFutureWatcher<int>* watcher = new QFutureWatcher<int>();
connect(watcher, &QFutureWatcher<int>::finished, [watcher]{
auto result = watcher->future().results();
qDebug() << result;
watcher->deleteLater();
});
watcher->setFuture(future);
3. 使用案例
3.1 多生产者 + 消费者
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "主线程: " << quint64(QThread::currentThreadId());
USafedQueue<int> queue;
// 启动多个消费者
for(int i=0;i<4;++i)
{
QtConcurrent::run([&]
{
int val;
while(queue.dequeue(val))
{
int result = val * val; // 处理数据
qDebug() << quint64(QThread::currentThreadId()) << "Consume: Res: " << result << queue.size();
}
});
}
QtConcurrent::run([&]{
for(int i=0;i<1000;++i){
queue.enqueue(i);
QThread::msleep(10); // 模拟生成速度
qDebug() << quint64(QThread::currentThreadId()) << "Produce: Res: " << i << queue.size();
}
queue.stop(); // 所有生产完成
});
qDebug() << "Exit...";
return a.exec();
}
5248 Consume: Res: 992016 0
2668 Produce: Res: 996 0
3712 Consume: Res: 994009 0
2668 Produce: Res: 997 0
20936 Consume: Res: 996004 0
2668 Produce: Res: 998 0
17040 Consume: Res: 998001 0
2668 Produce: Res: 999 0
本文来自博客园,作者:Hakuon,转载请注明原文链接:https://www.cnblogs.com/Hakuon/p/19821951
浙公网安备 33010602011771号