2022-10-27 11:59:09 +02:00
|
|
|
// Copyright (C) 2022 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2022-10-27 11:59:09 +02:00
|
|
|
|
|
|
|
|
#include "utils/asynctask.h"
|
|
|
|
|
|
2022-10-31 12:08:59 +01:00
|
|
|
#include "utils/algorithm.h"
|
|
|
|
|
|
2022-10-27 11:59:09 +02:00
|
|
|
#include <QtTest>
|
|
|
|
|
|
|
|
|
|
using namespace Utils;
|
|
|
|
|
|
|
|
|
|
class tst_AsyncTask : public QObject
|
|
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
|
void runAsync();
|
|
|
|
|
void crefFunction();
|
|
|
|
|
void futureSynchonizer();
|
2022-10-31 12:08:59 +01:00
|
|
|
void taskTree();
|
|
|
|
|
void mapReduce_data();
|
|
|
|
|
void mapReduce();
|
|
|
|
|
private:
|
|
|
|
|
QThreadPool m_threadPool;
|
2022-10-27 11:59:09 +02:00
|
|
|
};
|
|
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
void report3(QPromise<int> &promise)
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
promise.addResult(0);
|
|
|
|
|
promise.addResult(2);
|
|
|
|
|
promise.addResult(1);
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
void reportN(QPromise<double> &promise, int n)
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
|
promise.addResult(0);
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
void reportString1(QPromise<QString> &promise, const QString &s)
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
promise.addResult(s);
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
void reportString2(QPromise<QString> &promise, QString s)
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
promise.addResult(s);
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Callable {
|
|
|
|
|
public:
|
2023-02-11 18:43:19 +01:00
|
|
|
void operator()(QPromise<double> &promise, int n) const
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
|
promise.addResult(0);
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class MyObject {
|
|
|
|
|
public:
|
2023-02-11 18:43:19 +01:00
|
|
|
static void staticMember0(QPromise<double> &promise)
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
promise.addResult(0);
|
|
|
|
|
promise.addResult(2);
|
|
|
|
|
promise.addResult(1);
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
static void staticMember1(QPromise<double> &promise, int n)
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
|
promise.addResult(0);
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
void member0(QPromise<double> &promise) const
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
promise.addResult(0);
|
|
|
|
|
promise.addResult(2);
|
|
|
|
|
promise.addResult(1);
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
void member1(QPromise<double> &promise, int n) const
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
|
promise.addResult(0);
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
void memberString1(QPromise<QString> &promise, const QString &s) const
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
promise.addResult(s);
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
void memberString2(QPromise<QString> &promise, QString s) const
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
promise.addResult(s);
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
void nonConstMember(QPromise<double> &promise)
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
promise.addResult(0);
|
|
|
|
|
promise.addResult(2);
|
|
|
|
|
promise.addResult(1);
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-03-03 20:00:20 +01:00
|
|
|
template <typename...>
|
2023-02-11 18:43:19 +01:00
|
|
|
struct FutureArgType;
|
|
|
|
|
|
2023-03-03 20:00:20 +01:00
|
|
|
template <typename Arg>
|
2023-02-11 18:43:19 +01:00
|
|
|
struct FutureArgType<QFuture<Arg>>
|
|
|
|
|
{
|
|
|
|
|
using Type = Arg;
|
|
|
|
|
};
|
|
|
|
|
|
2023-03-03 20:00:20 +01:00
|
|
|
template <typename...>
|
2023-02-11 18:43:19 +01:00
|
|
|
struct ConcurrentResultType;
|
|
|
|
|
|
|
|
|
|
template<typename Function, typename ...Args>
|
|
|
|
|
struct ConcurrentResultType<Function, Args...>
|
|
|
|
|
{
|
|
|
|
|
using Type = typename FutureArgType<decltype(QtConcurrent::run(
|
|
|
|
|
std::declval<Function>(), std::declval<Args>()...))>::Type;
|
|
|
|
|
};
|
|
|
|
|
|
2022-10-27 11:59:09 +02:00
|
|
|
template <typename Function, typename ...Args,
|
2023-03-03 20:00:20 +01:00
|
|
|
typename ResultType = typename ConcurrentResultType<Function, Args...>::Type>
|
2023-02-11 18:43:19 +01:00
|
|
|
std::shared_ptr<AsyncTask<ResultType>> createAsyncTask(Function &&function, Args &&...args)
|
2022-10-27 11:59:09 +02:00
|
|
|
{
|
|
|
|
|
auto asyncTask = std::make_shared<AsyncTask<ResultType>>();
|
2023-02-11 18:43:19 +01:00
|
|
|
asyncTask->setConcurrentCallData(std::forward<Function>(function), std::forward<Args>(args)...);
|
2022-10-27 11:59:09 +02:00
|
|
|
asyncTask->start();
|
|
|
|
|
return asyncTask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tst_AsyncTask::runAsync()
|
|
|
|
|
{
|
|
|
|
|
// free function pointer
|
|
|
|
|
QCOMPARE(createAsyncTask(&report3)->results(),
|
|
|
|
|
QList<int>({0, 2, 1}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&report3).results(),
|
|
|
|
|
QList<int>({0, 2, 1}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(report3)->results(),
|
|
|
|
|
QList<int>({0, 2, 1}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(report3).results(),
|
|
|
|
|
QList<int>({0, 2, 1}));
|
2022-10-27 11:59:09 +02:00
|
|
|
|
|
|
|
|
QCOMPARE(createAsyncTask(reportN, 4)->results(),
|
|
|
|
|
QList<double>({0, 0, 0, 0}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(reportN, 4).results(),
|
|
|
|
|
QList<double>({0, 0, 0, 0}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(reportN, 2)->results(),
|
|
|
|
|
QList<double>({0, 0}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(reportN, 2).results(),
|
|
|
|
|
QList<double>({0, 0}));
|
2022-10-27 11:59:09 +02:00
|
|
|
|
|
|
|
|
QString s = QLatin1String("string");
|
|
|
|
|
const QString &crs = QLatin1String("cr string");
|
|
|
|
|
const QString cs = QLatin1String("c string");
|
|
|
|
|
|
|
|
|
|
QCOMPARE(createAsyncTask(reportString1, s)->results(),
|
|
|
|
|
QList<QString>({s}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(reportString1, s).results(),
|
|
|
|
|
QList<QString>({s}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(reportString1, crs)->results(),
|
|
|
|
|
QList<QString>({crs}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(reportString1, crs).results(),
|
|
|
|
|
QList<QString>({crs}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(reportString1, cs)->results(),
|
|
|
|
|
QList<QString>({cs}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(reportString1, cs).results(),
|
|
|
|
|
QList<QString>({cs}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(reportString1, QString(QLatin1String("rvalue")))->results(),
|
|
|
|
|
QList<QString>({QString(QLatin1String("rvalue"))}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(reportString1, QString(QLatin1String("rvalue"))).results(),
|
|
|
|
|
QList<QString>({QString(QLatin1String("rvalue"))}));
|
2022-10-27 11:59:09 +02:00
|
|
|
|
|
|
|
|
QCOMPARE(createAsyncTask(reportString2, s)->results(),
|
|
|
|
|
QList<QString>({s}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(reportString2, s).results(),
|
|
|
|
|
QList<QString>({s}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(reportString2, crs)->results(),
|
|
|
|
|
QList<QString>({crs}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(reportString2, crs).results(),
|
|
|
|
|
QList<QString>({crs}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(reportString2, cs)->results(),
|
|
|
|
|
QList<QString>({cs}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(reportString2, cs).results(),
|
|
|
|
|
QList<QString>({cs}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(reportString2, QString(QLatin1String("rvalue")))->results(),
|
|
|
|
|
QList<QString>({QString(QLatin1String("rvalue"))}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(reportString2, QString(QLatin1String("rvalue"))).results(),
|
|
|
|
|
QList<QString>({QString(QLatin1String("rvalue"))}));
|
2022-10-27 11:59:09 +02:00
|
|
|
|
|
|
|
|
// lambda
|
2023-02-11 18:43:19 +01:00
|
|
|
QCOMPARE(createAsyncTask([](QPromise<double> &promise, int n) {
|
|
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
|
promise.addResult(0);
|
2022-10-27 11:59:09 +02:00
|
|
|
}, 3)->results(),
|
|
|
|
|
QList<double>({0, 0, 0}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun([](QPromise<double> &promise, int n) {
|
|
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
|
promise.addResult(0);
|
|
|
|
|
}, 3).results(),
|
|
|
|
|
QList<double>({0, 0, 0}));
|
2022-10-27 11:59:09 +02:00
|
|
|
|
|
|
|
|
// std::function
|
2023-02-11 18:43:19 +01:00
|
|
|
const std::function<void(QPromise<double>&,int)> fun = [](QPromise<double> &promise, int n) {
|
|
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
|
promise.addResult(0);
|
2022-10-27 11:59:09 +02:00
|
|
|
};
|
|
|
|
|
QCOMPARE(createAsyncTask(fun, 2)->results(),
|
|
|
|
|
QList<double>({0, 0}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(fun, 2).results(),
|
|
|
|
|
QList<double>({0, 0}));
|
2022-10-27 11:59:09 +02:00
|
|
|
|
|
|
|
|
// operator()
|
|
|
|
|
QCOMPARE(createAsyncTask(Callable(), 3)->results(),
|
|
|
|
|
QList<double>({0, 0, 0}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(Callable(), 3).results(),
|
|
|
|
|
QList<double>({0, 0, 0}));
|
2022-10-27 11:59:09 +02:00
|
|
|
const Callable c{};
|
|
|
|
|
QCOMPARE(createAsyncTask(c, 2)->results(),
|
|
|
|
|
QList<double>({0, 0}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(c, 2).results(),
|
|
|
|
|
QList<double>({0, 0}));
|
2022-10-27 11:59:09 +02:00
|
|
|
|
|
|
|
|
// static member functions
|
|
|
|
|
QCOMPARE(createAsyncTask(&MyObject::staticMember0)->results(),
|
|
|
|
|
QList<double>({0, 2, 1}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::staticMember0).results(),
|
|
|
|
|
QList<double>({0, 2, 1}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(&MyObject::staticMember1, 2)->results(),
|
|
|
|
|
QList<double>({0, 0}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::staticMember1, 2).results(),
|
|
|
|
|
QList<double>({0, 0}));
|
2022-10-27 11:59:09 +02:00
|
|
|
|
|
|
|
|
// member functions
|
|
|
|
|
const MyObject obj{};
|
|
|
|
|
QCOMPARE(createAsyncTask(&MyObject::member0, &obj)->results(),
|
|
|
|
|
QList<double>({0, 2, 1}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::member0, &obj).results(),
|
|
|
|
|
QList<double>({0, 2, 1}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(&MyObject::member1, &obj, 4)->results(),
|
|
|
|
|
QList<double>({0, 0, 0, 0}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::member1, &obj, 4).results(),
|
|
|
|
|
QList<double>({0, 0, 0, 0}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(&MyObject::memberString1, &obj, s)->results(),
|
|
|
|
|
QList<QString>({s}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::memberString1, &obj, s).results(),
|
|
|
|
|
QList<QString>({s}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(&MyObject::memberString1, &obj, crs)->results(),
|
|
|
|
|
QList<QString>({crs}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::memberString1, &obj, crs).results(),
|
|
|
|
|
QList<QString>({crs}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(&MyObject::memberString1, &obj, cs)->results(),
|
|
|
|
|
QList<QString>({cs}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::memberString1, &obj, cs).results(),
|
|
|
|
|
QList<QString>({cs}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(&MyObject::memberString1, &obj, QString(QLatin1String("rvalue")))->results(),
|
|
|
|
|
QList<QString>({QString(QLatin1String("rvalue"))}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(),
|
|
|
|
|
QList<QString>({QString(QLatin1String("rvalue"))}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(&MyObject::memberString2, &obj, s)->results(),
|
|
|
|
|
QList<QString>({s}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::memberString2, &obj, s).results(),
|
|
|
|
|
QList<QString>({s}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(&MyObject::memberString2, &obj, crs)->results(),
|
|
|
|
|
QList<QString>({crs}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::memberString2, &obj, crs).results(),
|
|
|
|
|
QList<QString>({crs}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(&MyObject::memberString2, &obj, cs)->results(),
|
|
|
|
|
QList<QString>({cs}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::memberString2, &obj, cs).results(),
|
|
|
|
|
QList<QString>({cs}));
|
2022-10-27 11:59:09 +02:00
|
|
|
QCOMPARE(createAsyncTask(&MyObject::memberString2, &obj, QString(QLatin1String("rvalue")))->results(),
|
|
|
|
|
QList<QString>({QString(QLatin1String("rvalue"))}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(),
|
|
|
|
|
QList<QString>({QString(QLatin1String("rvalue"))}));
|
2022-10-27 11:59:09 +02:00
|
|
|
MyObject nonConstObj{};
|
|
|
|
|
QCOMPARE(createAsyncTask(&MyObject::nonConstMember, &nonConstObj)->results(),
|
|
|
|
|
QList<double>({0, 2, 1}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(&MyObject::nonConstMember, &nonConstObj).results(),
|
|
|
|
|
QList<double>({0, 2, 1}));
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tst_AsyncTask::crefFunction()
|
|
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
// free function pointer with promise
|
2022-10-27 11:59:09 +02:00
|
|
|
auto fun = &report3;
|
|
|
|
|
QCOMPARE(createAsyncTask(std::cref(fun))->results(),
|
|
|
|
|
QList<int>({0, 2, 1}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(std::cref(fun)).results(),
|
|
|
|
|
QList<int>({0, 2, 1}));
|
2022-10-27 11:59:09 +02:00
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
// lambda with promise
|
|
|
|
|
auto lambda = [](QPromise<double> &promise, int n) {
|
|
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
|
promise.addResult(0);
|
2022-10-27 11:59:09 +02:00
|
|
|
};
|
|
|
|
|
QCOMPARE(createAsyncTask(std::cref(lambda), 3)->results(),
|
|
|
|
|
QList<double>({0, 0, 0}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(std::cref(lambda), 3).results(),
|
|
|
|
|
QList<double>({0, 0, 0}));
|
2022-10-27 11:59:09 +02:00
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
// std::function with promise
|
|
|
|
|
const std::function<void(QPromise<double>&,int)> funObj = [](QPromise<double> &promise, int n) {
|
|
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
|
promise.addResult(0);
|
2022-10-27 11:59:09 +02:00
|
|
|
};
|
|
|
|
|
QCOMPARE(createAsyncTask(std::cref(funObj), 2)->results(),
|
|
|
|
|
QList<double>({0, 0}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(std::cref(funObj), 2).results(),
|
|
|
|
|
QList<double>({0, 0}));
|
2022-10-27 11:59:09 +02:00
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
// callable with promise
|
2022-10-27 11:59:09 +02:00
|
|
|
const Callable c{};
|
|
|
|
|
QCOMPARE(createAsyncTask(std::cref(c), 2)->results(),
|
|
|
|
|
QList<double>({0, 0}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(std::cref(c), 2).results(),
|
|
|
|
|
QList<double>({0, 0}));
|
2022-10-27 11:59:09 +02:00
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
// member functions with promise
|
2022-10-27 11:59:09 +02:00
|
|
|
auto member = &MyObject::member0;
|
|
|
|
|
const MyObject obj{};
|
|
|
|
|
QCOMPARE(createAsyncTask(std::cref(member), &obj)->results(),
|
|
|
|
|
QList<double>({0, 2, 1}));
|
2023-03-03 20:00:20 +01:00
|
|
|
QCOMPARE(Utils::asyncRun(std::cref(member), &obj).results(),
|
|
|
|
|
QList<double>({0, 2, 1}));
|
2022-10-27 11:59:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tst_AsyncTask::futureSynchonizer()
|
|
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
auto lambda = [](QPromise<int> &promise) {
|
2022-10-27 11:59:09 +02:00
|
|
|
while (true) {
|
2023-02-11 18:43:19 +01:00
|
|
|
if (promise.isCanceled()) {
|
|
|
|
|
promise.future().cancel();
|
|
|
|
|
promise.finish();
|
2022-10-27 11:59:09 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
QThread::msleep(100);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FutureSynchronizer synchronizer;
|
|
|
|
|
{
|
|
|
|
|
AsyncTask<int> task;
|
2023-02-11 18:43:19 +01:00
|
|
|
task.setConcurrentCallData(lambda);
|
2022-10-27 11:59:09 +02:00
|
|
|
task.setFutureSynchronizer(&synchronizer);
|
|
|
|
|
task.start();
|
|
|
|
|
QThread::msleep(10);
|
|
|
|
|
// We assume here that worker thread will still work for about 90 ms.
|
|
|
|
|
QVERIFY(!task.isCanceled());
|
|
|
|
|
QVERIFY(!task.isDone());
|
|
|
|
|
}
|
|
|
|
|
synchronizer.flushFinishedFutures();
|
|
|
|
|
QVERIFY(!synchronizer.isEmpty());
|
|
|
|
|
// The destructor of synchronizer should wait for about 90 ms for worker thread to be canceled
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
void multiplyBy2(QPromise<int> &promise, int input) { promise.addResult(input * 2); }
|
2022-10-31 12:08:59 +01:00
|
|
|
|
|
|
|
|
void tst_AsyncTask::taskTree()
|
|
|
|
|
{
|
|
|
|
|
using namespace Tasking;
|
|
|
|
|
|
|
|
|
|
int value = 1;
|
|
|
|
|
|
|
|
|
|
const auto setupIntAsync = [&](AsyncTask<int> &task) {
|
2023-02-11 18:43:19 +01:00
|
|
|
task.setConcurrentCallData(multiplyBy2, value);
|
2022-10-31 12:08:59 +01:00
|
|
|
};
|
|
|
|
|
const auto handleIntAsync = [&](const AsyncTask<int> &task) {
|
|
|
|
|
value = task.result();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const Group root {
|
|
|
|
|
Async<int>(setupIntAsync, handleIntAsync),
|
|
|
|
|
Async<int>(setupIntAsync, handleIntAsync),
|
|
|
|
|
Async<int>(setupIntAsync, handleIntAsync),
|
|
|
|
|
Async<int>(setupIntAsync, handleIntAsync),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TaskTree tree(root);
|
|
|
|
|
|
|
|
|
|
QEventLoop eventLoop;
|
|
|
|
|
connect(&tree, &TaskTree::done, &eventLoop, &QEventLoop::quit);
|
|
|
|
|
tree.start();
|
|
|
|
|
eventLoop.exec();
|
|
|
|
|
|
|
|
|
|
QCOMPARE(value, 16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int returnxx(int x)
|
|
|
|
|
{
|
|
|
|
|
return x * x;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-11 18:43:19 +01:00
|
|
|
static void returnxxWithPromise(QPromise<int> &promise, int x)
|
2022-10-31 12:08:59 +01:00
|
|
|
{
|
2023-02-11 18:43:19 +01:00
|
|
|
promise.addResult(x * x);
|
2022-10-31 12:08:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static double s_sum = 0;
|
|
|
|
|
static QList<double> s_results;
|
|
|
|
|
|
|
|
|
|
void tst_AsyncTask::mapReduce_data()
|
|
|
|
|
{
|
|
|
|
|
using namespace Tasking;
|
|
|
|
|
|
|
|
|
|
QTest::addColumn<Group>("root");
|
|
|
|
|
QTest::addColumn<double>("sum");
|
|
|
|
|
QTest::addColumn<QList<double>>("results");
|
|
|
|
|
|
|
|
|
|
const auto initTree = [] {
|
|
|
|
|
s_sum = 0;
|
|
|
|
|
s_results.append(s_sum);
|
|
|
|
|
};
|
|
|
|
|
const auto setupAsync = [](AsyncTask<int> &task, int input) {
|
2023-02-11 18:43:19 +01:00
|
|
|
task.setConcurrentCallData(returnxx, input);
|
2022-10-31 12:08:59 +01:00
|
|
|
};
|
|
|
|
|
const auto setupAsyncWithFI = [](AsyncTask<int> &task, int input) {
|
2023-02-11 18:43:19 +01:00
|
|
|
task.setConcurrentCallData(returnxxWithPromise, input);
|
2022-10-31 12:08:59 +01:00
|
|
|
};
|
|
|
|
|
const auto setupAsyncWithTP = [this](AsyncTask<int> &task, int input) {
|
2023-02-11 18:43:19 +01:00
|
|
|
task.setConcurrentCallData(returnxx, input);
|
2022-10-31 12:08:59 +01:00
|
|
|
task.setThreadPool(&m_threadPool);
|
|
|
|
|
};
|
|
|
|
|
const auto handleAsync = [](const AsyncTask<int> &task) {
|
|
|
|
|
s_sum += task.result();
|
|
|
|
|
s_results.append(task.result());
|
|
|
|
|
};
|
|
|
|
|
const auto handleTreeParallel = [] {
|
|
|
|
|
s_sum /= 2;
|
|
|
|
|
s_results.append(s_sum);
|
|
|
|
|
Utils::sort(s_results); // mapping order is undefined
|
|
|
|
|
};
|
|
|
|
|
const auto handleTreeSequential = [] {
|
|
|
|
|
s_sum /= 2;
|
|
|
|
|
s_results.append(s_sum);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using namespace Tasking;
|
|
|
|
|
using namespace std::placeholders;
|
|
|
|
|
|
|
|
|
|
using SetupHandler = std::function<void(AsyncTask<int> &task, int input)>;
|
|
|
|
|
using DoneHandler = std::function<void()>;
|
|
|
|
|
|
|
|
|
|
const auto createTask = [=](const TaskItem &executeMode,
|
|
|
|
|
const SetupHandler &setupHandler,
|
|
|
|
|
const DoneHandler &doneHandler) {
|
|
|
|
|
return Group {
|
|
|
|
|
executeMode,
|
|
|
|
|
OnGroupSetup(initTree),
|
|
|
|
|
Async<int>(std::bind(setupHandler, _1, 1), handleAsync),
|
|
|
|
|
Async<int>(std::bind(setupHandler, _1, 2), handleAsync),
|
|
|
|
|
Async<int>(std::bind(setupHandler, _1, 3), handleAsync),
|
|
|
|
|
Async<int>(std::bind(setupHandler, _1, 4), handleAsync),
|
|
|
|
|
Async<int>(std::bind(setupHandler, _1, 5), handleAsync),
|
|
|
|
|
OnGroupDone(doneHandler)
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const Group parallelRoot = createTask(parallel, setupAsync, handleTreeParallel);
|
|
|
|
|
const Group parallelRootWithFI = createTask(parallel, setupAsyncWithFI, handleTreeParallel);
|
|
|
|
|
const Group parallelRootWithTP = createTask(parallel, setupAsyncWithTP, handleTreeParallel);
|
|
|
|
|
const Group sequentialRoot = createTask(sequential, setupAsync, handleTreeSequential);
|
|
|
|
|
const Group sequentialRootWithFI = createTask(sequential, setupAsyncWithFI, handleTreeSequential);
|
|
|
|
|
const Group sequentialRootWithTP = createTask(sequential, setupAsyncWithTP, handleTreeSequential);
|
|
|
|
|
|
|
|
|
|
const double defaultSum = 27.5;
|
|
|
|
|
const QList<double> defaultResult{0., 1., 4., 9., 16., 25., 27.5};
|
|
|
|
|
|
|
|
|
|
QTest::newRow("Parallel") << parallelRoot << defaultSum << defaultResult;
|
|
|
|
|
QTest::newRow("ParallelWithFutureInterface") << parallelRootWithFI << defaultSum << defaultResult;
|
|
|
|
|
QTest::newRow("ParallelWithThreadPool") << parallelRootWithTP << defaultSum << defaultResult;
|
|
|
|
|
QTest::newRow("Sequential") << sequentialRoot << defaultSum << defaultResult;
|
|
|
|
|
QTest::newRow("SequentialWithFutureInterface") << sequentialRootWithFI << defaultSum << defaultResult;
|
|
|
|
|
QTest::newRow("SequentialWithThreadPool") << sequentialRootWithTP << defaultSum << defaultResult;
|
|
|
|
|
|
|
|
|
|
const auto setupSimpleAsync = [](AsyncTask<int> &task, int input) {
|
2023-02-11 18:43:19 +01:00
|
|
|
task.setConcurrentCallData([](int input) { return input * 2; }, input);
|
2022-10-31 12:08:59 +01:00
|
|
|
};
|
|
|
|
|
const auto handleSimpleAsync = [](const AsyncTask<int> &task) {
|
|
|
|
|
s_sum += task.result() / 4.;
|
|
|
|
|
s_results.append(s_sum);
|
|
|
|
|
};
|
|
|
|
|
const Group simpleRoot = {
|
|
|
|
|
sequential,
|
|
|
|
|
OnGroupSetup([] { s_sum = 0; }),
|
|
|
|
|
Async<int>(std::bind(setupSimpleAsync, _1, 1), handleSimpleAsync),
|
|
|
|
|
Async<int>(std::bind(setupSimpleAsync, _1, 2), handleSimpleAsync),
|
|
|
|
|
Async<int>(std::bind(setupSimpleAsync, _1, 3), handleSimpleAsync)
|
|
|
|
|
};
|
|
|
|
|
QTest::newRow("Simple") << simpleRoot << 3.0 << QList<double>({.5, 1.5, 3.});
|
|
|
|
|
|
|
|
|
|
const auto setupStringAsync = [](AsyncTask<int> &task, const QString &input) {
|
2023-02-11 18:43:19 +01:00
|
|
|
task.setConcurrentCallData([](const QString &input) -> int { return input.size(); }, input);
|
2022-10-31 12:08:59 +01:00
|
|
|
};
|
|
|
|
|
const auto handleStringAsync = [](const AsyncTask<int> &task) {
|
|
|
|
|
s_sum /= task.result();
|
|
|
|
|
};
|
|
|
|
|
const Group stringRoot = {
|
|
|
|
|
parallel,
|
|
|
|
|
OnGroupSetup([] { s_sum = 90.0; }),
|
|
|
|
|
Async<int>(std::bind(setupStringAsync, _1, "blubb"), handleStringAsync),
|
|
|
|
|
Async<int>(std::bind(setupStringAsync, _1, "foo"), handleStringAsync),
|
|
|
|
|
Async<int>(std::bind(setupStringAsync, _1, "blah"), handleStringAsync)
|
|
|
|
|
};
|
|
|
|
|
QTest::newRow("String") << stringRoot << 1.5 << QList<double>({});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tst_AsyncTask::mapReduce()
|
|
|
|
|
{
|
|
|
|
|
QThreadPool pool;
|
|
|
|
|
|
|
|
|
|
s_sum = 0;
|
|
|
|
|
s_results.clear();
|
|
|
|
|
|
|
|
|
|
using namespace Tasking;
|
|
|
|
|
|
|
|
|
|
QFETCH(Group, root);
|
|
|
|
|
QFETCH(double, sum);
|
|
|
|
|
QFETCH(QList<double>, results);
|
|
|
|
|
|
|
|
|
|
TaskTree tree(root);
|
|
|
|
|
|
|
|
|
|
QEventLoop eventLoop;
|
|
|
|
|
connect(&tree, &TaskTree::done, &eventLoop, &QEventLoop::quit);
|
|
|
|
|
tree.start();
|
|
|
|
|
eventLoop.exec();
|
|
|
|
|
|
|
|
|
|
QCOMPARE(s_results, results);
|
|
|
|
|
QCOMPARE(s_sum, sum);
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 11:59:09 +02:00
|
|
|
QTEST_GUILESS_MAIN(tst_AsyncTask)
|
|
|
|
|
|
|
|
|
|
#include "tst_asynctask.moc"
|