本文主要是介绍深入理解Qt多线程编程(QtConcurrent),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
多线程编程在现代软件开发中变得越来越重要,它能够提高应用程序的响应速度和处理性能。在Qt框架中,除了QThreadPool,QtConcurrent也是一个强大的工具,用于简化和管理多线程编程。
目录
- 概述
- 接口详解
- QtConcurrent::run
- QtConcurrent::map
- QtConcurrent::mapped
- QtConcurrent::filter和filtered
- QtConcurrent::filteredReduced
- QtConcurrent::mappedReduced
- QtConcurrent::blockingXXXXX系列
- 注意
- 场景一:有多个并行任务需要开启
- 场景二:在并行任务处理过程中需要处理其他业务
- 场景三:需要并行任务处理的结果作为其他业务的输入
概述
QtConcurrent模块提供了一组便捷的函数,用于在不显式创建和管理线程的情况下实现并发编程。它通过将任务提交给线程池来执行,从而避免了频繁创建和销毁线程带来的性能开销。QtConcurrent非常适合处理需要并行执行的批量任务,并且能够自动管理线程和任务的分配。
接口详解
QtConcurrent::run
QtConcurrent::run
用于将一个可调用对象(如函数、Lambda表达式或成员函数)提交给线程池执行。这个函数适用于简单的并行任务。
使用案例
执行简单的任务
void myFunction() {qDebug() << "Function is running in thread" << QThread::currentThread();QThread::sleep(2);qDebug() << "Function completed in thread" << QThread::currentThread();
}int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QFuture<void> future = QtConcurrent::run(myFunction);future.waitForFinished(); // 等待任务完成return app.exec();
}
执行带返回值的任务
int myFunction()
{qDebug() << "Function is running in thread" << QThread::currentThreadId();QThread::sleep(1);qDebug() << "Function completed in thread" << QThread::currentThreadId();return 1;
}int main(int argc, char* argv[])
{QApplication a(argc, argv);QFuture<int> future = QtConcurrent::run(myFunction);future.waitForFinished(); // 等待任务完成int result = future.result();qDebug() << "received value: " << result;return a.exec();
}
执行带返回值和参数的任务
int square(int num)
{qDebug() << "Function is running in thread" << QThread::currentThreadId();return num * num;
}int main(int argc, char* argv[])
{QApplication a(argc, argv);QFuture<int> future = QtConcurrent::run(square, 2);future.waitForFinished(); // 等待任务完成int result = future.result();qDebug() << "received value: " << result;return a.exec();
}
执行Lambda表达式任务
int main(int argc, char* argv[])
{QApplication a(argc, argv);QFuture<int> future = QtConcurrent::run([]() {qDebug() << "Function is running in thread" << QThread::currentThreadId();return 2;});future.waitForFinished(); // 等待任务完成int result = future.result();qDebug() << "received value: " << result;return a.exec();
}
修改引用传递的参数
void square(int& num)
{qDebug() << "Function is running in thread" << QThread::currentThreadId();num *= num;
}int main(int argc, char* argv[])
{QApplication a(argc, argv);int num = 2;QFuture<void> future = QtConcurrent::run(square, std::ref(num));future.waitForFinished(); // 等待任务完成qDebug() << "result value: " << num;return a.exec();
}
执行可调用对象任务
struct square {void operator()(int n) { num = n; }int num = 1;
};int main(int argc, char* argv[])
{QApplication a(argc, argv);square sq;qDebug() << "value: " << sq.num; // out: value: 1// 这里不是修改sq对象,修改的是sq备份的对象,因为run函数的参数默认是值传递QtConcurrent::run(sq, 10).waitForFinished();qDebug() << "value: " << sq.num; // out: value: 1QtConcurrent::run(std::ref(sq), 20).waitForFinished(); // 通过引用传递才有效qDebug() << "value: " << sq.num; // out: value: 20return a.exec();
}
源码解析
QtConcurrent::run
函数的源码:
template <typename T, typename Param1, typename Arg1>
QFuture<T> run(T (*functionPointer)(Param1), const Arg1 &arg1)
{return (new StoredFunctorCall1<T, T (*)(Param1), Arg1>(functionPointer, arg1))->start();
}
... 其他重载不列举了
可以看到run
函数是new
了一个对象,我们直接看这个对象的源码:
template <typename T, typename FunctionPointer, typename Arg1>
struct StoredFunctorCall1: public RunFunctionTask<T>
{inline StoredFunctorCall1(FunctionPointer _function, const Arg1 &_arg1): function(_function), arg1(_arg1) {}void runFunctor() override { this->result = function(arg1); }FunctionPointer function;Arg1 arg1;
};
这段代码需要关注函数runFunctor()
,以及基类RunFunctionTask
:
template <typename T>
class RunFunctionTask : public RunFunctionTaskBase<T>
{
public:void run() override{if (this->isCanceled()) {this->reportFinished();return;}
#ifndef QT_NO_EXCEPTIONStry {
#endifthis->runFunctor();
#ifndef QT_NO_EXCEPTIONS} catch (QException &e) {QFutureInterface<T>::reportException(e);} catch (...) {QFutureInterface<T>::reportException(QUnhandledException());}
#endifthis->reportResult(result);this->reportFinished();}T result;
};
这段代码需要关注:
- 重载
run
函数,并在函数内调用了this->runFunctor()
,是StoredFunctorCall1
类的接口,其实就是调用了QtConcurrent::run
传入的可调用对象。
这里重载的是
QRunnable
的run
函数,下面代码可以看出它们的继承关系。
this->reportResult(result);
这里把线程函数的返回值记录下来。- 基类
RunFunctionTaskBase
template <typename T>
class RunFunctionTaskBase : public QFutureInterface<T> , public QRunnable
{
public:QFuture<T> start(){return start(QThreadPool::globalInstance());}QFuture<T> start(QThreadPool *pool){this->setThreadPool(pool);this->setRunnable(this);this->reportStarted();QFuture<T> theFuture = this->future();pool->start(this, /*m_priority*/ 0);return theFuture;}void run() override {}virtual void runFunctor() = 0;
};
这里需要关注:
解析总结
QtConcurrent::run()
实现原理:创建一个QRunnable
子类对象,重载run()
,在run()
函数内调用线程函数,并将结果通过QFutureInterface
记录下来。所有Runnable
都是通过QThreadPool
来执行,可以用全局的线程池对象,也可以自定义线程池对象。
QtConcurrent::map
QtConcurrent::map
函数用于并行地修改序列中的每个元素。它将一个函数应用于容器或迭代器指定范围的每个元素,这个函数会直接修改元素。由于操作是并行执行的,map 函数可以显著加快处理速度,特别是在处理大数据集时。
使用案例
并发修改Qt容器数据
void square(int& n)
{n *= n;
}int main(int argc, char* argv[])
{QList<int> listDatas = { 1, 2, 3, 4, 5 };QtConcurrent::map(listDatas, square).waitForFinished();qDebug() << listDatas;QVector<int> vecDatas = { 1, 2, 3, 4, 5 };QtConcurrent::map(vecDatas, square).waitForFinished();qDebug() << vecDatas;QQueue<int> queDatas;for (int i = 1; i < 6; ++i)queDatas.append(i);QtConcurrent::map(queDatas, square).waitForFinished();qDebug() << queDatas;QMap<int, int> mapDatas = { { 1, 1 }, { 2, 2 }, { 3, 3 } };QtConcurrent::map(mapDatas, square).waitForFinished();qDebug() << mapDatas;QStack<int> stackDatas;for (int i = 1; i < 6; ++i)stackDatas.append(i);QtConcurrent::map(stackDatas, square).waitForFinished();qDebug() << stackDatas;// error: no match for call to '(QtConcurrent::FunctionWrapper1<void, int&>) (const int&)// QSet<int> setDatas = { 1, 2, 3, 4, 5 };// QtConcurrent::map(setDatas, square).waitForFinished();// qDebug() << setDatas;return 0;
}
并发修改标准库容器数据
void square(int& n)
{n *= n;
}int main(int argc, char* argv[])
{QApplication a(argc, argv);std::list<int> listDatas = { 1, 2, 3, 4, 5 };QtConcurrent::map(listDatas, square).waitForFinished();qDebug() << listDatas;std::vector<int> vecDatas = { 1, 2, 3, 4, 5 };QtConcurrent::map(vecDatas, square).waitForFinished();qDebug() << vecDatas;std::deque<int> deqDatas = { 1, 2, 3, 4, 5 };QtConcurrent::map(deqDatas, square).waitForFinished();for (auto data : deqDatas) {qDebug() << data;}std::array<int, 5> aryDatas = { 1, 2, 3, 4, 5 };QtConcurrent::map(aryDatas, square).waitForFinished();for (auto data : aryDatas) {qDebug() << data;}// error: no match for call to '(QtConcurrent::FunctionWrapper1<void, int&>) (std::pair<const int, int>&)// std::map<int, int> mapDatas = { { 1, 1 }, { 2, 2 }, { 3, 3 } };// QtConcurrent::map(mapDatas, square).waitForFinished();// qDebug() << mapDatas;// error: no match for call to '(QtConcurrent::FunctionWrapper1<void, int&>) (const int&)// std::set<int> setDatas = { 1, 2, 3, 4, 5 };// QtConcurrent::map(setDatas, square).waitForFinished();// for (auto data : setDatas) {// qDebug() << data;// }return a.exec();
}
注意:
标准库中的std::map
和std::set
是不支持的。
QtConcurrent::map
为什么能支持QMap
,但不支持std::map
?
请看后面的源码解析
源码解析
QtConcurrent::map
源码:
// map() on sequences
template <typename Sequence, typename MapFunctor>
QFuture<void> map(Sequence &sequence, MapFunctor map)
{return startMap(sequence.begin(), sequence.end(), QtPrivate::createFunctionWrapper(map));
}// map() on iterators
template <typename Iterator, typename MapFunctor>
QFuture<void> map(Iterator begin, Iterator end, MapFunctor map)
{return startMap(begin, end, QtPrivate::createFunctionWrapper(map));
}
这里可以看到,底层就是调用了startMap
,并且数据都通过收尾迭代器传入。
template <typename Iterator, typename Functor>
inline ThreadEngineStarter<void> startMap(Iterator begin, Iterator end, Functor functor)
{return startThreadEngine(new MapKernel<Iterator, Functor>(begin, end, functor));
}
这段代码是调用线程进行处理数据,但在这之前需要把数据和可调用对象functor
整合在一个结构中:
// map kernel, works with both parallel-for and parallel-while
template <typename Iterator, typename MapFunctor>
class MapKernel : public IterateKernel<Iterator, void>
{MapFunctor map;
public:typedef void ReturnType;MapKernel(Iterator begin, Iterator end, MapFunctor _map): IterateKernel<Iterator, void>(begin, end), map(_map){ }bool runIteration(Iterator it, int, void *) override{map(*it);return false;}bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, void *) override{Iterator it = sequenceBeginIterator;std::advance(it, beginIndex);for (int i = beginIndex; i < endIndex; ++i) {runIteration(it, i, nullptr);std::advance(it, 1);}return false;}
};
代码中的map
就是可调用对象(即处理数据的线程函数),在runIteration
函数内调用了map(*it)
,所以这里就是将容器元素一个一个传给可调用对象进行处理的,而且都是通过迭代器的解引用来获取数据的。
上面使用案例提到的问题,为什么支持QMap,但不支持std::map?
是因为QMap::iterator
指向的是键值对中的value,解引用后得到的是具体的value值;
而std::map::iterator
指向的是键值对(如std::pair(const int, int)
),所以当std::map
作为数据传入时会报错:no match for call to '(QtConcurrent::FunctionWrapper1<void, int&>) (std::pair<const int, int>&)'
。
所以只要容器的迭代器指向的数据类型能和可调用对象的参数类型一致,QtConcurrent::map
就能够支持。
QtConcurrent::mapped
QtConcurrent::mapped
和QtConcurrent::map
非常相近,区别就是后者是直接修改原始容器中的数据,而前者不会修改原始容器中的数据,它会创建一个新的结果容器。
使用案例
并发处理Qt容器数据
int square(int n)
{n *= n;return n;
}int main(int argc, char* argv[])
{QList<int> listDatas = { 1, 2, 3, 4, 5 };auto listFuture = QtConcurrent::mapped(listDatas, square);listFuture.waitForFinished();qDebug() << listDatas << listFuture.results();QVector<int> vecDatas = { 1, 2, 3, 4, 5 };auto vecFutrure = QtConcurrent::mapped(vecDatas, square);vecFutrure.waitForFinished();qDebug() << vecDatas << vecFutrure.results();QQueue<int> queDatas;for (int i = 1; i < 6; ++i)queDatas.append(i);auto queFuture = QtConcurrent::mapped(queDatas, square);queFuture.waitForFinished();qDebug() << queDatas << queFuture.results();QMap<int, int> mapDatas = { { 1, 1 }, { 5, 5 }, { 3, 3 } };auto mapFuture = QtConcurrent::mapped(mapDatas, square);mapFuture.waitForFinished();qDebug() << mapDatas << mapFuture.results();QStack<int> stackDatas;for (int i = 1; i < 6; ++i)stackDatas.append(i);auto stackFuture = QtConcurrent::mapped(stackDatas, square);stackFuture.waitForFinished();qDebug() << stackDatas << stackFuture.results();QSet<int> setDatas = { 1, 2, 3, 4, 5 };auto setFuture = QtConcurrent::mapped(setDatas, square);setFuture.waitForFinished();qDebug() << setDatas << setFuture.results();return 0;
}
并发处理标准库容器数据
int square(int n)
{n *= n;return n;
}int main(int argc, char* argv[])
{QApplication a(argc, argv);std::list<int> listDatas = { 1, 2, 3, 4, 5 };auto listFuture = QtConcurrent::mapped(listDatas, square);listFuture.waitForFinished();qDebug() << listDatas << listFuture.results();std::vector<int> vecDatas = { 1, 2, 3, 4, 5 };auto vecFuture = QtConcurrent::mapped(vecDatas, square);vecFuture.waitForFinished();qDebug() << vecDatas << vecFuture.results();std::deque<int> deqDatas = { 1, 2, 3, 4, 5 };auto deqFuture = QtConcurrent::mapped(deqDatas, square);deqFuture.waitForFinished();for (auto data : deqDatas) {qDebug() << data;}qDebug() << deqFuture.results();std::array<int, 5> aryDatas = { 1, 2, 3, 4, 5 };auto aryFuture = QtConcurrent::mapped(aryDatas, square);aryFuture.waitForFinished();for (auto data : aryDatas) {qDebug() << data;}qDebug() << aryFuture.results();std::set<int> setDatas = { 1, 2, 3, 4, 5 };auto setFuture = QtConcurrent::mapped(setDatas, square);setFuture.waitForFinished();for (auto data : setDatas) {qDebug() << data;}qDebug() << setFuture.results();// error: no match for call to '(QtConcurrent::FunctionWrapper1<int, int>) (std::pair<const int, int>&)// std::map<int, int> mapDatas = { { 1, 1 }, { 2, 2 }, { 3, 3 } };// auto mapFuture = QtConcurrent::mapped(mapDatas, square);// qDebug() << mapDatas << mapFuture.results();return a.exec();
}
QtConcurrent::filter和filtered
这两个函数就是对容器中的数据进行筛选,filter
是直接修改原始容器中的数据,而filtered
是创建新容器来存储结果。
使用案例
bool isEven(int num)
{return num % 2 == 0;
}int main(int argc, char* argv[])
{QVector<int> data = { 1, 2, 3, 4, 5, 6 };// 使用filter筛选数据QFuture<void> filterFuture = QtConcurrent::filter(data, isEven);filterFuture.waitForFinished();for (int value : data) {qDebug() << "Filtered value:" << value;}// 使用filtered筛选数据并获取结果QFuture<int> filteredFuture = QtConcurrent::filtered(data, isEven);filteredFuture.waitForFinished();QList<int> filteredResult = filteredFuture.results();for (int value : filteredResult) {qDebug() << "Filtered result value:" << value;}return 0;
}
这两个接口具体支持哪些类型的容器可以参考
QtConcurrent::map
和mapped
系列章节内容。
QtConcurrent::filteredReduced
QtConcurrent::filteredReduced
函数有两部操作,第一步是先过滤数据,第二步是将过滤的数据整合成一个值。函数原型:
template <typename ResultType, typename Sequence, typename KeepFunctor, typename ReduceFunctor>
QFuture<ResultType> filteredReduced(const Sequence &sequence,KeepFunctor keep,ReduceFunctor reduce,ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce))
sequence
:原始容器数据keep
:这是一个过滤函数,用来决定元素是否需要被处理的可调用对象。每个元素都会调用该函数,只有此函数返回true
时,元素才会被后面的reduce
处理。reduce
:是一个归约函数,就是把经过过滤的数据整合成一个值。options
:归约操作选项,用来控制归约操作的顺序:
使用案例
将字符串容器中以逗号结尾的元素拼接起来
std::random_device rd; // 用于获取种子
std::mt19937 gen(rd()); // 标准 mersenne_twister_engine 初始化
int generateRandomInteger(int min, int max)
{std::uniform_int_distribution<> distrib(min, max); // 定义一个分布return distrib(gen);
}// 过滤函数:检查字符串是否以逗号结尾
bool endsWithComma(const QString& str)
{// 通过随机延时来改变每次过滤函数的执行时间QThread::msleep(generateRandomInteger(1, 500));return str.endsWith(",");
}// 归约函数:将字符串拼接到结果中
void concatenateStrings(QString& result, const QString& str)
{result += str;
}int main(int argc, char* argv[])
{// 创建一个包含字符串的 QStringListQStringList strings = { "hello,", "world", "example,", "test", "code," };for (int i = 10; i < 99; i++) {if (i % 2 == 0)strings.append(QString::number(i) + ",");elsestrings.append(QString::number(i));}auto future = QtConcurrent::filteredReduced(strings, endsWithComma, concatenateStrings);future.waitForFinished();qDebug() << "DefaultReduce results:" << future.result() << Qt::endl;future = QtConcurrent::filteredReduced(strings, endsWithComma, concatenateStrings, QtConcurrent::UnorderedReduce);future.waitForFinished();qDebug() << "UnorderedReduce1 results:" << future.result() << Qt::endl;future = QtConcurrent::filteredReduced(strings, endsWithComma, concatenateStrings, QtConcurrent::UnorderedReduce);future.waitForFinished();qDebug() << "UnorderedReduce2 results:" << future.result() << Qt::endl;future = QtConcurrent::filteredReduced(strings, endsWithComma, concatenateStrings, QtConcurrent::OrderedReduce);future.waitForFinished();qDebug() << "OrderedReduce1 results:" << future.result() << Qt::endl;future = QtConcurrent::filteredReduced(strings, endsWithComma, concatenateStrings, QtConcurrent::OrderedReduce);future.waitForFinished();qDebug() << "OrderedReduce2 results:" << future.result() << Qt::endl;return 0;
}
上面代码在过滤函数中使用随机延时来使每次执行时元素过滤的顺序不一致,从而来验证UnorderedReduce
和OrderedReduce
两个枚举值对归约函数的影响。结果如下:
DefaultReduce results: "code,22,28,24,example,32,12,18,hello,10,16,26,20,48,36,38,14,40,50,34,58,30,46,44,56,72,42,52,54,66,80,78,84,62,60,68,70,64,82,74,76,92,88,86,90,94,96,98," UnorderedReduce1 results: "24,code,26,14,hello,example,18,32,20,12,30,22,16,36,10,48,44,28,46,50,34,58,38,64,42,52,40,66,62,78,56,74,54,70,82,86,60,80,68,84,76,72,90,88,94,92,96,98," UnorderedReduce2 results: "hello,18,code,16,14,24,22,32,26,30,40,10,20,28,12,example,42,44,46,50,38,48,34,52,54,36,62,72,68,56,64,70,86,88,60,58,90,78,84,74,80,66,82,76,98,96,92,94," OrderedReduce1 results: "hello,example,code,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98," OrderedReduce2 results: "hello,example,code,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,"
从结果可以看出,使用OrderedReduce
枚举时,输出结果是一致的;而UnorderedReduce
枚举的输出结果是不一致的。
源码解析
// Implementation of filter-reduce
template <typename ReducedResultType,typename Iterator,typename KeepFunctor,typename ReduceFunctor,typename Reducer = ReduceKernel<ReduceFunctor,ReducedResultType,typename qValueType<Iterator>::value_type> >
class FilteredReducedKernel : public IterateKernel<Iterator, ReducedResultType>
{...bool runIteration(Iterator it, int index, ReducedResultType *) override{IntermediateResults<typename qValueType<Iterator>::value_type> results;results.begin = index;results.end = index + 1;if (keep(*it))results.vector.append(*it);reducer.runReduce(reduce, reducedResult, results);return false;}...
};
这里直接展示QtConcurrent::filteredReduced
函数底层最核心的代码,代码中FilteredReducedKernel::runIteration
就是用来处理每一个元素的函数,函数内先调用了keep
(过滤函数),如果返回true
则把元素放到results
中,然后再调用reducer.runReduce
(归约函数)来处理结果。
QtConcurrent::mappedReduced
QtConcurrent::mappedReduced
函数原型:
template <typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor>
QFuture<ResultType> mappedReduced(const Sequence &sequence,MapFunctor map,ReduceFunctor reduce,ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce))
该函数和QtConcurrent::filteredReduced
非常相似,唯一的区别就是第二个参数:MapFunctor map
。filteredReduced
函数是先经过KeepFunctor
过滤,过滤后再经过ReduceFunctor
整合处理成一个值;而mappedReduced
函数是先经过MapFunctor
处理,处理得到的返回值给ReduceFunctor
整合处理成一个值。
这里我把
MapFunctor
称为映射函数,ReduceFunctor
称为归约函数
使用案例
计算所有元素的平方和
// 平方处理
int square(int x)
{return x * x;
}// 求和处理
void sum(int& result, int value)
{result += value;
}int main(int argc, char* argv[])
{QVector<int> numbers = { 1, 2, 3, 4, 5 };auto result = QtConcurrent::mappedReduced(numbers, square, sum);result.waitForFinished(); // 等待操作完成qDebug() << "The sum of squares is:" << result.result();return 1;
}
源码解析
template <typename ReducedResultType,typename Iterator,typename MapFunctor,typename ReduceFunctor,typename Reducer = ReduceKernel<ReduceFunctor,ReducedResultType,typename MapFunctor::result_type> >
class MappedReducedKernel : public IterateKernel<Iterator, ReducedResultType>
{...bool runIteration(Iterator it, int index, ReducedResultType *) override{IntermediateResults<typename MapFunctor::result_type> results;results.begin = index;results.end = index + 1;results.vector.append(map(*it));reducer.runReduce(reduce, reducedResult, results);return false;}...
};
这里直接展示QtConcurrent::mappedReduced
函数底层最核心的代码,代码中MappedReducedKernel::runIteration
就是用来处理每一个元素的函数,函数内先调用了map
(映射函数),把返回值放到results
中,然后再调用reducer.runReduce
(归约函数)来处理结果。
QtConcurrent::blockingXXXXX系列
blockingXXXXX
系列的接口其实就是在原有的非阻塞并行处理接口(比如:filter
、filtered
、map
、mapped
、filteredReduced
、mappedReduced
等)的基础上,增加了阻塞调用线程直到所有操作完成的特性。
比如QtConcurrent::map(listDatas, square).waitForFinished();
这行代码等同于:QtConcurrent::blockingMap(listDatas, square);
。
注意
前面介绍的接口中分为非阻塞接口和阻塞接口,阻塞接口就是以blockingXXX
开头的接口,其他都是非阻塞接口。在实际的应用场景中,我们可能有时候需要非阻塞的,有时候又需要阻塞的,怎么区分呢?下面我们通过场景来举例说明:
场景一:有多个并行任务需要开启
两组数据求平方和
// 平方处理
int square(int x)
{QThread::sleep(1); // 模拟耗时操作return x * x;
}// 求和处理
void sum(int& result, int value)
{result += value;
}int main(int argc, char* argv[])
{QVector<int> numbers1 = { 1, 2, 3, 4, 5 };QVector<int> numbers2 = { 1, 2, 3, 4, 5 };auto result1 = QtConcurrent::mappedReduced(numbers1, square, sum);auto result2 = QtConcurrent::mappedReduced(numbers2, square, sum);result1.waitForFinished();result2.waitForFinished();qDebug() << "The sum of squares is:" << result2.result() + result2.result();return 1;
}
场景二:在并行任务处理过程中需要处理其他业务
例如:在数据求平方和的过程中处理其他业务
// 平方处理
int square(int x)
{QThread::sleep(1); // 模拟耗时操作return x * x;
}// 求和处理
void sum(int& result, int value)
{result += value;
}int main(int argc, char* argv[])
{QVector<int> numbers = { 1, 2, 3, 4, 5 };auto result = QtConcurrent::mappedReduced(numbers, square, sum);while (result.isFinished()) {// 模拟处理其他业务的耗时操作QThread::sleep(1);}qDebug() << "The sum of squares is:" << result.result();return 1;
}
场景三:需要并行任务处理的结果作为其他业务的输入
例如:数据求平方和的结果作为输出
// 平方处理
int square(int x)
{QThread::sleep(1); // 模拟耗时操作return x * x;
}// 求和处理
void sum(int& result, int value)
{result += value;
}int main(int argc, char* argv[])
{QVector<int> numbers = { 1, 2, 3, 4, 5 };auto result = QtConcurrent::blockingMappedReduced(numbers, square, sum);// 平方和的结果作为其他业务(输出字符串)的输入qDebug() << "The sum of squares is:" << result;return 1;
}
这篇关于深入理解Qt多线程编程(QtConcurrent)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!