diff options
Diffstat (limited to 'tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp')
-rw-r--r-- | tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp | 636 |
1 files changed, 445 insertions, 191 deletions
diff --git a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp index e4b728f950..0bc2961903 100644 --- a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp +++ b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp @@ -1,34 +1,16 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qtconcurrentrun.h> -#include <qfuture.h> +#include <QFuture> +#include <QMutex> +#include <QMutexLocker> #include <QString> -#include <QtTest/QtTest> +#include <QWaitCondition> +#include <QTest> +#include <QTimer> +#include <QFutureSynchronizer> + +#include <QtTest/private/qemulationdetector_p.h> using namespace QtConcurrent; @@ -36,6 +18,7 @@ class tst_QtConcurrentRun: public QObject { Q_OBJECT private slots: + void initTestCase(); void runLightFunction(); void runHeavyFunction(); void returnValue(); @@ -48,14 +31,20 @@ private slots: void recursive(); #ifndef QT_NO_EXCEPTIONS void exceptions(); + void unhandledException(); #endif void functor(); void lambda(); void callableObjectWithState(); void withPromise(); void withPromiseInThreadPool(); + void withPromiseAndThen(); void moveOnlyType(); void crefFunction(); + void customPromise(); + void nonDefaultConstructibleValue(); + void nullThreadPool(); + void nullThreadPoolNoLeak(); }; void light() @@ -97,6 +86,13 @@ void heavy() qDebug("done function"); } +void tst_QtConcurrentRun::initTestCase() +{ + // proxy check for QEMU; catches slightly more though + if (QTestPrivate::isRunningArmOnX86()) + QSKIP("Runs into spurious crashes on QEMU -- QTBUG-106906"); +} + void tst_QtConcurrentRun::runLightFunction() { qDebug("starting function"); @@ -121,14 +117,14 @@ void tst_QtConcurrentRun::runLightFunction() void (*f3)(QPromise<int> &) = lightOverloaded; qDebug("starting function with promise"); - QFuture<void> future3 = runWithPromise(f3); + QFuture<int> future3 = run(f3); qDebug("waiting"); future3.waitForFinished(); qDebug("done"); void (*f4)(QPromise<double> &, int v) = lightOverloaded; qDebug("starting function with promise and with arg"); - QFuture<void> future4 = runWithPromise(f4, 2); + QFuture<double> future4 = run(f4, 2); qDebug("waiting"); future4.waitForFinished(); qDebug("done"); @@ -428,141 +424,141 @@ void tst_QtConcurrentRun::reportValueWithPromise() QThreadPool pool; QFuture<int> f; - f = runWithPromise(reportInt0); + f = run(reportInt0); QCOMPARE(f.result(), 0); - f = runWithPromise(&pool, reportInt0); + f = run(&pool, reportInt0); QCOMPARE(f.result(), 0); - f = runWithPromise(reportIntPlusOne, 5); + f = run(reportIntPlusOne, 5); QCOMPARE(f.result(), 6); - f = runWithPromise(&pool, reportIntPlusOne, 5); + f = run(&pool, reportIntPlusOne, 5); QCOMPARE(f.result(), 6); AWithPromise a; - f = runWithPromise(&AWithPromise::member0, &a); + f = run(&AWithPromise::member0, &a); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, &AWithPromise::member0, &a); + f = run(&pool, &AWithPromise::member0, &a); QCOMPARE(f.result(), 10); - f = runWithPromise(&AWithPromise::member1, &a, 20); + f = run(&AWithPromise::member1, &a, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(&pool, &AWithPromise::member1, &a, 20); + f = run(&pool, &AWithPromise::member1, &a, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(&AWithPromise::member0, a); + f = run(&AWithPromise::member0, a); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, &AWithPromise::member0, a); + f = run(&pool, &AWithPromise::member0, a); QCOMPARE(f.result(), 10); - f = runWithPromise(&AWithPromise::member1, a, 20); + f = run(&AWithPromise::member1, a, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(&pool, &AWithPromise::member1, a, 20); + f = run(&pool, &AWithPromise::member1, a, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(a); + f = run(a); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, a); + f = run(&pool, a); QCOMPARE(f.result(), 10); - f = runWithPromise(std::ref(a)); + f = run(std::ref(a)); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, std::ref(a)); + f = run(&pool, std::ref(a)); QCOMPARE(f.result(), 10); const AConstWithPromise aConst = AConstWithPromise(); - f = runWithPromise(&AConstWithPromise::member0, &aConst); + f = run(&AConstWithPromise::member0, &aConst); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, &AConstWithPromise::member0, &aConst); + f = run(&pool, &AConstWithPromise::member0, &aConst); QCOMPARE(f.result(), 10); - f = runWithPromise(&AConstWithPromise::member1, &aConst, 20); + f = run(&AConstWithPromise::member1, &aConst, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(&pool, &AConstWithPromise::member1, &aConst, 20); + f = run(&pool, &AConstWithPromise::member1, &aConst, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(&AConstWithPromise::member0, aConst); + f = run(&AConstWithPromise::member0, aConst); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, &AConstWithPromise::member0, aConst); + f = run(&pool, &AConstWithPromise::member0, aConst); QCOMPARE(f.result(), 10); - f = runWithPromise(&AConstWithPromise::member1, aConst, 20); + f = run(&AConstWithPromise::member1, aConst, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(&pool, &AConstWithPromise::member1, aConst, 20); + f = run(&pool, &AConstWithPromise::member1, aConst, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(aConst); + f = run(aConst); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, aConst); + f = run(&pool, aConst); QCOMPARE(f.result(), 10); - f = runWithPromise(std::ref(a)); + f = run(std::ref(a)); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, std::ref(a)); + f = run(&pool, std::ref(a)); QCOMPARE(f.result(), 10); ANoExceptWithPromise aNoExcept; - f = runWithPromise(&ANoExceptWithPromise::member0, &aNoExcept); + f = run(&ANoExceptWithPromise::member0, &aNoExcept); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, &ANoExceptWithPromise::member0, &aNoExcept); + f = run(&pool, &ANoExceptWithPromise::member0, &aNoExcept); QCOMPARE(f.result(), 10); - f = runWithPromise(&ANoExceptWithPromise::member1, &aNoExcept, 20); + f = run(&ANoExceptWithPromise::member1, &aNoExcept, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(&pool, &ANoExceptWithPromise::member1, &aNoExcept, 20); + f = run(&pool, &ANoExceptWithPromise::member1, &aNoExcept, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(&ANoExceptWithPromise::member0, aNoExcept); + f = run(&ANoExceptWithPromise::member0, aNoExcept); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, &ANoExceptWithPromise::member0, aNoExcept); + f = run(&pool, &ANoExceptWithPromise::member0, aNoExcept); QCOMPARE(f.result(), 10); - f = runWithPromise(&ANoExceptWithPromise::member1, aNoExcept, 20); + f = run(&ANoExceptWithPromise::member1, aNoExcept, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(&pool, &ANoExceptWithPromise::member1, aNoExcept, 20); + f = run(&pool, &ANoExceptWithPromise::member1, aNoExcept, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(aNoExcept); + f = run(aNoExcept); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, aNoExcept); + f = run(&pool, aNoExcept); QCOMPARE(f.result(), 10); - f = runWithPromise(std::ref(aNoExcept)); + f = run(std::ref(aNoExcept)); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, std::ref(aNoExcept)); + f = run(&pool, std::ref(aNoExcept)); QCOMPARE(f.result(), 10); const AConstNoExceptWithPromise aConstNoExcept = AConstNoExceptWithPromise(); - f = runWithPromise(&AConstNoExceptWithPromise::member0, &aConstNoExcept); + f = run(&AConstNoExceptWithPromise::member0, &aConstNoExcept); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, &AConstNoExceptWithPromise::member0, &aConstNoExcept); + f = run(&pool, &AConstNoExceptWithPromise::member0, &aConstNoExcept); QCOMPARE(f.result(), 10); - f = runWithPromise(&AConstNoExceptWithPromise::member1, &aConstNoExcept, 20); + f = run(&AConstNoExceptWithPromise::member1, &aConstNoExcept, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(&pool, &AConstNoExceptWithPromise::member1, &aConstNoExcept, 20); + f = run(&pool, &AConstNoExceptWithPromise::member1, &aConstNoExcept, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(&AConstNoExceptWithPromise::member0, aConstNoExcept); + f = run(&AConstNoExceptWithPromise::member0, aConstNoExcept); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, &AConstNoExceptWithPromise::member0, aConstNoExcept); + f = run(&pool, &AConstNoExceptWithPromise::member0, aConstNoExcept); QCOMPARE(f.result(), 10); - f = runWithPromise(&AConstNoExceptWithPromise::member1, aConstNoExcept, 20); + f = run(&AConstNoExceptWithPromise::member1, aConstNoExcept, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(&pool, &AConstNoExceptWithPromise::member1, aConstNoExcept, 20); + f = run(&pool, &AConstNoExceptWithPromise::member1, aConstNoExcept, 20); QCOMPARE(f.result(), 20); - f = runWithPromise(aConstNoExcept); + f = run(aConstNoExcept); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, aConstNoExcept); + f = run(&pool, aConstNoExcept); QCOMPARE(f.result(), 10); - f = runWithPromise(std::ref(aConstNoExcept)); + f = run(std::ref(aConstNoExcept)); QCOMPARE(f.result(), 10); - f = runWithPromise(&pool, std::ref(aConstNoExcept)); + f = run(&pool, std::ref(aConstNoExcept)); QCOMPARE(f.result(), 10); } @@ -670,10 +666,10 @@ void tst_QtConcurrentRun::implicitConvertibleTypes() { QThreadPool pool; - double d; + double d = 0.0; run(doubleFunction, d).waitForFinished(); run(&pool, doubleFunction, d).waitForFinished(); - int i; + int i = 0; run(doubleFunction, d).waitForFinished(); run(&pool, doubleFunction, d).waitForFinished(); run(doubleFunction, i).waitForFinished(); @@ -819,7 +815,7 @@ public: void run() override { int iter = 60; while (--iter && !cancel.loadRelaxed()) - QThread::currentThread()->msleep(25); + QThread::currentThread()->sleep(std::chrono::milliseconds{25}); } }; @@ -890,6 +886,25 @@ void tst_QtConcurrentRun::exceptions() QVERIFY2(caught, "did not get exception"); } + +void tst_QtConcurrentRun::unhandledException() +{ + struct Exception {}; + bool caught = false; + try { + auto f = QtConcurrent::run([] { throw Exception {}; }); + f.waitForFinished(); + } catch (const QUnhandledException &e) { + try { + if (e.exception()) + std::rethrow_exception(e.exception()); + } catch (const Exception &) { + caught = true; + } + } + + QVERIFY(caught); +} #endif // Compiler supports decltype @@ -940,14 +955,14 @@ void tst_QtConcurrentRun::functor() } FunctorWithPromise fWithPromise; { - QtConcurrent::runWithPromise(fWithPromise, 1.5).waitForFinished(); + QtConcurrent::run(fWithPromise, 1.5).waitForFinished(); } OverloadedFunctorWithPromise ofWithPromise; { - QtConcurrent::runWithPromise<int>(ofWithPromise).waitForFinished(); - QtConcurrent::runWithPromise<double>(ofWithPromise).waitForFinished(); - QtConcurrent::runWithPromise<int>(ofWithPromise, 1).waitForFinished(); - QtConcurrent::runWithPromise<double>(ofWithPromise, 1).waitForFinished(); + QtConcurrent::run<int>(ofWithPromise).waitForFinished(); + QtConcurrent::run<double>(ofWithPromise).waitForFinished(); + QtConcurrent::run<int>(ofWithPromise, 1).waitForFinished(); + QtConcurrent::run<double>(ofWithPromise, 1).waitForFinished(); } // and now with explicit pool: QThreadPool pool; @@ -975,13 +990,17 @@ void tst_QtConcurrentRun::functor() // Compiler supports lambda void tst_QtConcurrentRun::lambda() { - QCOMPARE(QtConcurrent::run([](){ return 45; }).result(), 45); - QCOMPARE(QtConcurrent::run([](int a){ return a+15; }, 12).result(), 12+15); - QCOMPARE(QtConcurrent::run([](int a, double b){ return a + b; }, 12, 15).result(), double(12+15)); - QCOMPARE(QtConcurrent::run([](int a , int, int, int, int b){ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5); + QCOMPARE(QtConcurrent::run([]() { return 45; }).result(), 45); + QCOMPARE(QtConcurrent::run([](int a) { return a+15; }, 12).result(), 12+15); + QCOMPARE(QtConcurrent::run([](int a, double b) { return a + b; }, 12, 15).result(), + double(12+15)); + QCOMPARE(QtConcurrent::run([](int a , int, int, int, int b) + { return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5); - QCOMPARE(QtConcurrent::runWithPromise([](QPromise<int> &promise){ promise.addResult(45); }).result(), 45); - QCOMPARE(QtConcurrent::runWithPromise([](QPromise<int> &promise, double input){ promise.addResult(input / 2.0); }, 15.0).result(), 7); + QCOMPARE(QtConcurrent::run([](QPromise<int> &promise) + { promise.addResult(45); }).result(), 45); + QCOMPARE(QtConcurrent::run([](QPromise<int> &promise, double input) + { promise.addResult(input / 2.0); }, 15.0).result(), 7); { QString str { "Hello World Foo" }; @@ -992,10 +1011,12 @@ void tst_QtConcurrentRun::lambda() // and now with explicit pool: QThreadPool pool; - QCOMPARE(QtConcurrent::run(&pool, [](){ return 45; }).result(), 45); - QCOMPARE(QtConcurrent::run(&pool, [](int a){ return a+15; }, 12).result(), 12+15); - QCOMPARE(QtConcurrent::run(&pool, [](int a, double b){ return a + b; }, 12, 15).result(), double(12+15)); - QCOMPARE(QtConcurrent::run(&pool, [](int a , int, int, int, int b){ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5); + QCOMPARE(QtConcurrent::run(&pool, []() { return 45; }).result(), 45); + QCOMPARE(QtConcurrent::run(&pool, [](int a) { return a + 15; }, 12).result(), 12 + 15); + QCOMPARE(QtConcurrent::run(&pool, [](int a, double b) + { return a + b; }, 12, 15).result(), double(12 + 15)); + QCOMPARE(QtConcurrent::run(&pool, [](int a , int, int, int, int b) + { return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5); { QString str { "Hello World Foo" }; @@ -1045,19 +1066,20 @@ void tst_QtConcurrentRun::callableObjectWithState() CallableWithStateWithPromise oWithPromise; // Run method setNewState explicitly - runWithPromise(&CallableWithStateWithPromise::setNewState, &oWithPromise, CallableWithStateWithPromise::defaultState() + 1).waitForFinished(); + run(&CallableWithStateWithPromise::setNewState, &oWithPromise, + CallableWithStateWithPromise::defaultState() + 1).waitForFinished(); QCOMPARE(oWithPromise.state, CallableWithStateWithPromise::defaultState() + 1); // Run operator()(int) explicitly - runWithPromise(std::ref(oWithPromise), CallableWithStateWithPromise::defaultState() + 2).waitForFinished(); + run(std::ref(oWithPromise), CallableWithStateWithPromise::defaultState() + 2).waitForFinished(); QCOMPARE(oWithPromise.state, CallableWithStateWithPromise::defaultState() + 2); // Run on a copy of object (original object remains unchanged) - runWithPromise(oWithPromise, CallableWithStateWithPromise::defaultState() + 3).waitForFinished(); + run(oWithPromise, CallableWithStateWithPromise::defaultState() + 3).waitForFinished(); QCOMPARE(oWithPromise.state, CallableWithStateWithPromise::defaultState() + 2); // Explicitly run on a temporary object - QCOMPARE(runWithPromise(CallableWithStateWithPromise(), 15).result(), 15); + QCOMPARE(run(CallableWithStateWithPromise(), 15).result(), 15); } void report3(QPromise<int> &promise) @@ -1067,12 +1089,25 @@ void report3(QPromise<int> &promise) promise.addResult(1); } +static void staticReport3(QPromise<int> &promise) +{ + promise.addResult(0); + promise.addResult(2); + promise.addResult(1); +} + void reportN(QPromise<double> &promise, int n) { for (int i = 0; i < n; ++i) promise.addResult(0); } +static void staticReportN(QPromise<double> &promise, int n) +{ + for (int i = 0; i < n; ++i) + promise.addResult(0); +} + void reportString1(QPromise<QString> &promise, const QString &s) { promise.addResult(s); @@ -1141,40 +1176,50 @@ public: void tst_QtConcurrentRun::withPromise() { // free function pointer - QCOMPARE(runWithPromise(&report3).results(), + QCOMPARE(run(&report3).results(), QList<int>({0, 2, 1})); - QCOMPARE(runWithPromise(report3).results(), + QCOMPARE(run(report3).results(), QList<int>({0, 2, 1})); - QCOMPARE(runWithPromise(reportN, 4).results(), - QList<double>({0, 0, 0, 0})); - QCOMPARE(runWithPromise(reportN, 2).results(), + QCOMPARE(run(&staticReport3).results(), + QList<int>({0, 2, 1})); + QCOMPARE(run(staticReport3).results(), + QList<int>({0, 2, 1})); + + QCOMPARE(run(&reportN, 2).results(), + QList<double>({0, 0})); + QCOMPARE(run(reportN, 2).results(), + QList<double>({0, 0})); + + QCOMPARE(run(&staticReportN, 2).results(), + QList<double>({0, 0})); + QCOMPARE(run(staticReportN, 2).results(), QList<double>({0, 0})); QString s = QLatin1String("string"); const QString &crs = QLatin1String("cr string"); const QString cs = QLatin1String("c string"); - QCOMPARE(runWithPromise(reportString1, s).results(), + QCOMPARE(run(reportString1, s).results(), QList<QString>({s})); - QCOMPARE(runWithPromise(reportString1, crs).results(), + QCOMPARE(run(reportString1, crs).results(), QList<QString>({crs})); - QCOMPARE(runWithPromise(reportString1, cs).results(), + QCOMPARE(run(reportString1, cs).results(), QList<QString>({cs})); - QCOMPARE(runWithPromise(reportString1, QString(QLatin1String("rvalue"))).results(), + QCOMPARE(run(reportString1, QString(QLatin1String("rvalue"))).results(), QList<QString>({QString(QLatin1String("rvalue"))})); - QCOMPARE(runWithPromise(reportString2, s).results(), + QCOMPARE(run(reportString2, s).results(), QList<QString>({s})); - QCOMPARE(runWithPromise(reportString2, crs).results(), + QCOMPARE(run(reportString2, crs).results(), QList<QString>({crs})); - QCOMPARE(runWithPromise(reportString2, cs).results(), + QCOMPARE(run(reportString2, cs).results(), QList<QString>({cs})); - QCOMPARE(runWithPromise(reportString2, QString(QLatin1String("rvalue"))).results(), + QCOMPARE(run(reportString2, QString(QLatin1String("rvalue"))).results(), QList<QString>({QString(QLatin1String("rvalue"))})); // lambda - QCOMPARE(runWithPromise([](QPromise<double> &promise, int n) { + QCOMPARE(run([](QPromise<double> &promise, int n) { for (int i = 0; i < n; ++i) promise.addResult(0); }, 3).results(), @@ -1185,46 +1230,46 @@ void tst_QtConcurrentRun::withPromise() for (int i = 0; i < n; ++i) promise.addResult(0); }; - QCOMPARE(runWithPromise(fun, 2).results(), + QCOMPARE(run(fun, 2).results(), QList<double>({0, 0})); // operator() - QCOMPARE(runWithPromise(Callable(), 3).results(), + QCOMPARE(run(Callable(), 3).results(), QList<double>({0, 0, 0})); const Callable c{}; - QCOMPARE(runWithPromise(c, 2).results(), + QCOMPARE(run(c, 2).results(), QList<double>({0, 0})); // static member functions - QCOMPARE(runWithPromise(&MyObject::staticMember0).results(), + QCOMPARE(run(&MyObject::staticMember0).results(), QList<double>({0, 2, 1})); - QCOMPARE(runWithPromise(&MyObject::staticMember1, 2).results(), + QCOMPARE(run(&MyObject::staticMember1, 2).results(), QList<double>({0, 0})); // member functions const MyObject obj{}; - QCOMPARE(runWithPromise(&MyObject::member0, &obj).results(), + QCOMPARE(run(&MyObject::member0, &obj).results(), QList<double>({0, 2, 1})); - QCOMPARE(runWithPromise(&MyObject::member1, &obj, 4).results(), + QCOMPARE(run(&MyObject::member1, &obj, 4).results(), QList<double>({0, 0, 0, 0})); - QCOMPARE(runWithPromise(&MyObject::memberString1, &obj, s).results(), + QCOMPARE(run(&MyObject::memberString1, &obj, s).results(), QList<QString>({s})); - QCOMPARE(runWithPromise(&MyObject::memberString1, &obj, crs).results(), + QCOMPARE(run(&MyObject::memberString1, &obj, crs).results(), QList<QString>({crs})); - QCOMPARE(runWithPromise(&MyObject::memberString1, &obj, cs).results(), + QCOMPARE(run(&MyObject::memberString1, &obj, cs).results(), QList<QString>({cs})); - QCOMPARE(runWithPromise(&MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(), + QCOMPARE(run(&MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(), QList<QString>({QString(QLatin1String("rvalue"))})); - QCOMPARE(runWithPromise(&MyObject::memberString2, &obj, s).results(), + QCOMPARE(run(&MyObject::memberString2, &obj, s).results(), QList<QString>({s})); - QCOMPARE(runWithPromise(&MyObject::memberString2, &obj, crs).results(), + QCOMPARE(run(&MyObject::memberString2, &obj, crs).results(), QList<QString>({crs})); - QCOMPARE(runWithPromise(&MyObject::memberString2, &obj, cs).results(), + QCOMPARE(run(&MyObject::memberString2, &obj, cs).results(), QList<QString>({cs})); - QCOMPARE(runWithPromise(&MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(), + QCOMPARE(run(&MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(), QList<QString>({QString(QLatin1String("rvalue"))})); MyObject nonConstObj{}; - QCOMPARE(runWithPromise(&MyObject::nonConstMember, &nonConstObj).results(), + QCOMPARE(run(&MyObject::nonConstMember, &nonConstObj).results(), QList<double>({0, 2, 1})); } @@ -1232,40 +1277,50 @@ void tst_QtConcurrentRun::withPromiseInThreadPool() { QScopedPointer<QThreadPool> pool(new QThreadPool); // free function pointer - QCOMPARE(runWithPromise(pool.data(), &report3).results(), + QCOMPARE(run(pool.data(), &report3).results(), QList<int>({0, 2, 1})); - QCOMPARE(runWithPromise(pool.data(), report3).results(), + QCOMPARE(run(pool.data(), report3).results(), QList<int>({0, 2, 1})); - QCOMPARE(runWithPromise(pool.data(), reportN, 4).results(), - QList<double>({0, 0, 0, 0})); - QCOMPARE(runWithPromise(pool.data(), reportN, 2).results(), + QCOMPARE(run(pool.data(), &staticReport3).results(), + QList<int>({0, 2, 1})); + QCOMPARE(run(pool.data(), staticReport3).results(), + QList<int>({0, 2, 1})); + + QCOMPARE(run(pool.data(), &reportN, 2).results(), + QList<double>({0, 0})); + QCOMPARE(run(pool.data(), reportN, 2).results(), + QList<double>({0, 0})); + + QCOMPARE(run(pool.data(), &staticReportN, 2).results(), + QList<double>({0, 0})); + QCOMPARE(run(pool.data(), staticReportN, 2).results(), QList<double>({0, 0})); QString s = QLatin1String("string"); const QString &crs = QLatin1String("cr string"); const QString cs = QLatin1String("c string"); - QCOMPARE(runWithPromise(pool.data(), reportString1, s).results(), + QCOMPARE(run(pool.data(), reportString1, s).results(), QList<QString>({s})); - QCOMPARE(runWithPromise(pool.data(), reportString1, crs).results(), + QCOMPARE(run(pool.data(), reportString1, crs).results(), QList<QString>({crs})); - QCOMPARE(runWithPromise(pool.data(), reportString1, cs).results(), + QCOMPARE(run(pool.data(), reportString1, cs).results(), QList<QString>({cs})); - QCOMPARE(runWithPromise(pool.data(), reportString1, QString(QLatin1String("rvalue"))).results(), + QCOMPARE(run(pool.data(), reportString1, QString(QLatin1String("rvalue"))).results(), QList<QString>({QString(QLatin1String("rvalue"))})); - QCOMPARE(runWithPromise(pool.data(), reportString2, s).results(), + QCOMPARE(run(pool.data(), reportString2, s).results(), QList<QString>({s})); - QCOMPARE(runWithPromise(pool.data(), reportString2, crs).results(), + QCOMPARE(run(pool.data(), reportString2, crs).results(), QList<QString>({crs})); - QCOMPARE(runWithPromise(pool.data(), reportString2, cs).results(), + QCOMPARE(run(pool.data(), reportString2, cs).results(), QList<QString>({cs})); - QCOMPARE(runWithPromise(pool.data(), reportString2, QString(QLatin1String("rvalue"))).results(), + QCOMPARE(run(pool.data(), reportString2, QString(QLatin1String("rvalue"))).results(), QList<QString>({QString(QLatin1String("rvalue"))})); // lambda - QCOMPARE(runWithPromise(pool.data(), [](QPromise<double> &promise, int n) { + QCOMPARE(run(pool.data(), [](QPromise<double> &promise, int n) { for (int i = 0; i < n; ++i) promise.addResult(0); }, 3).results(), @@ -1276,46 +1331,153 @@ void tst_QtConcurrentRun::withPromiseInThreadPool() for (int i = 0; i < n; ++i) promise.addResult(0); }; - QCOMPARE(runWithPromise(pool.data(), fun, 2).results(), + QCOMPARE(run(pool.data(), fun, 2).results(), QList<double>({0, 0})); // operator() - QCOMPARE(runWithPromise(pool.data(), Callable(), 3).results(), + QCOMPARE(run(pool.data(), Callable(), 3).results(), QList<double>({0, 0, 0})); const Callable c{}; - QCOMPARE(runWithPromise(pool.data(), c, 2).results(), + QCOMPARE(run(pool.data(), c, 2).results(), QList<double>({0, 0})); // static member functions - QCOMPARE(runWithPromise(pool.data(), &MyObject::staticMember0).results(), + QCOMPARE(run(pool.data(), &MyObject::staticMember0).results(), QList<double>({0, 2, 1})); - QCOMPARE(runWithPromise(pool.data(), &MyObject::staticMember1, 2).results(), + QCOMPARE(run(pool.data(), &MyObject::staticMember1, 2).results(), QList<double>({0, 0})); // member functions const MyObject obj{}; - QCOMPARE(runWithPromise(pool.data(), &MyObject::member0, &obj).results(), + QCOMPARE(run(pool.data(), &MyObject::member0, &obj).results(), QList<double>({0, 2, 1})); - QCOMPARE(runWithPromise(pool.data(), &MyObject::member1, &obj, 4).results(), + QCOMPARE(run(pool.data(), &MyObject::member1, &obj, 4).results(), QList<double>({0, 0, 0, 0})); - QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString1, &obj, s).results(), + QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, s).results(), QList<QString>({s})); - QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString1, &obj, crs).results(), + QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, crs).results(), QList<QString>({crs})); - QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString1, &obj, cs).results(), + QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, cs).results(), QList<QString>({cs})); - QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(), + QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, + QString(QLatin1String("rvalue"))).results(), QList<QString>({QString(QLatin1String("rvalue"))})); - QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString2, &obj, s).results(), + QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, s).results(), QList<QString>({s})); - QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString2, &obj, crs).results(), + QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, crs).results(), QList<QString>({crs})); - QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString2, &obj, cs).results(), + QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, cs).results(), QList<QString>({cs})); - QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(), + QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, + QString(QLatin1String("rvalue"))).results(), QList<QString>({QString(QLatin1String("rvalue"))})); } +void tst_QtConcurrentRun::withPromiseAndThen() +{ + bool runExecuted = false; + bool cancelReceivedBeforeSync = false; + bool cancelReceivedAfterSync = false; + + bool syncBegin = false; + bool syncEnd = false; + + QMutex mutex; + QWaitCondition condition; + + auto reset = [&]() { + runExecuted = false; + cancelReceivedBeforeSync = false; + cancelReceivedAfterSync = false; + syncBegin = false; + syncEnd = false; + }; + + auto setFlag = [&mutex, &condition] (bool &flag) { + QMutexLocker locker(&mutex); + flag = true; + condition.wakeOne(); + }; + + auto waitForFlag = [&mutex, &condition] (const bool &flag) { + QMutexLocker locker(&mutex); + while (!flag) + condition.wait(&mutex); + }; + + auto report1WithCancel = [&](QPromise<int> &promise) { + runExecuted = true; + cancelReceivedBeforeSync = promise.isCanceled(); + + setFlag(syncBegin); + waitForFlag(syncEnd); + + cancelReceivedAfterSync = promise.isCanceled(); + if (cancelReceivedAfterSync) + return; + promise.addResult(1); + }; + + { + auto future = run(report1WithCancel); + + waitForFlag(syncBegin); + future.cancel(); + setFlag(syncEnd); + + future.waitForFinished(); + QCOMPARE(future.results().size(), 0); + QVERIFY(runExecuted); + QVERIFY(!cancelReceivedBeforeSync); + QVERIFY(cancelReceivedAfterSync); + } + + reset(); + + { + bool thenExecuted = false; + bool cancelExecuted = false; + auto future = run(report1WithCancel); + auto resultFuture = future.then(QtFuture::Launch::Async, [&](int) { thenExecuted = true; }) + .onCanceled([&]() { cancelExecuted = true; }); + + waitForFlag(syncBegin); + // no cancel this time + setFlag(syncEnd); + + resultFuture.waitForFinished(); + QCOMPARE(future.results().size(), 1); + QCOMPARE(future.result(), 1); + QVERIFY(runExecuted); + QVERIFY(thenExecuted); + QVERIFY(!cancelExecuted); + QVERIFY(!cancelReceivedBeforeSync); + QVERIFY(!cancelReceivedAfterSync); + } + + reset(); + + { + bool thenExecuted = false; + bool cancelExecuted = false; + auto future = run(report1WithCancel); + auto resultFuture = future.then(QtFuture::Launch::Async, [&](int) { thenExecuted = true; }) + .onCanceled([&]() { cancelExecuted = true; }); + + waitForFlag(syncBegin); + future.cancel(); + setFlag(syncEnd); + + resultFuture.waitForFinished(); + QCOMPARE(future.results().size(), 0); + QVERIFY(runExecuted); + QVERIFY(!thenExecuted); + QVERIFY(cancelExecuted); + QVERIFY(!cancelReceivedBeforeSync); + QVERIFY(cancelReceivedAfterSync); + } +} + class MoveOnlyType { public: @@ -1337,43 +1499,135 @@ public: void tst_QtConcurrentRun::moveOnlyType() { - QCOMPARE(runWithPromise(MoveOnlyCallable(), MoveOnlyType()).results(), + QCOMPARE(run(MoveOnlyCallable(), MoveOnlyType()).results(), QList<int>({1})); } void tst_QtConcurrentRun::crefFunction() { - // free function pointer with promise - auto fun = &report3; - QCOMPARE(runWithPromise(std::cref(fun)).results(), - QList<int>({0, 2, 1})); + { + // free function pointer with promise + auto fun = &returnInt0; + QCOMPARE(run(std::cref(fun)).result(), 10); + + // lambda with promise + auto lambda = [](int n) { + return 2 * n; + }; + QCOMPARE(run(std::cref(lambda), 3).result(), 6); + + // std::function with promise + const std::function<int(int)> funObj = [](int n) { + return 2 * n; + }; + QCOMPARE(run(std::cref(funObj), 2).result(), 4); + + // callable with promise + const AConst c{}; + QCOMPARE(run(std::cref(c), 2).result(), 2); + + // member functions with promise + auto member = &AConst::member0; + const AConst obj{}; + QCOMPARE(run(std::cref(member), &obj).result(), 10); + } - // lambda with promise - auto lambda = [](QPromise<double> &promise, int n) { - for (int i = 0; i < n; ++i) - promise.addResult(0); - }; - QCOMPARE(runWithPromise(std::cref(lambda), 3).results(), - QList<double>({0, 0, 0})); + { + // free function pointer with promise + auto fun = &report3; + QCOMPARE(run(std::cref(fun)).results(), + QList<int>({0, 2, 1})); + + // lambda with promise + auto lambda = [](QPromise<double> &promise, int n) { + for (int i = 0; i < n; ++i) + promise.addResult(0); + }; + QCOMPARE(run(std::cref(lambda), 3).results(), + QList<double>({0, 0, 0})); + + // 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); + }; + QCOMPARE(run(std::cref(funObj), 2).results(), + QList<double>({0, 0})); + + // callable with promise + const Callable c{}; + QCOMPARE(run(std::cref(c), 2).results(), + QList<double>({0, 0})); + + // member functions with promise + auto member = &MyObject::member0; + const MyObject obj{}; + QCOMPARE(run(std::cref(member), &obj).results(), + QList<double>({0, 2, 1})); + } +} - // 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); +int explicitPromise(QPromise<int> &promise, int &i) +{ + promise.setProgressRange(-10, 10); + ++i; + return i * 2; +} + +void tst_QtConcurrentRun::customPromise() +{ + QPromise<int> p; + int i = 4; + QCOMPARE(QtConcurrent::run(explicitPromise, std::ref(p), std::ref(i)).result(), 10); + QCOMPARE(i, 5); + QCOMPARE(p.future().progressMinimum(), -10); + QCOMPARE(p.future().progressMaximum(), 10); +} + +void tst_QtConcurrentRun::nonDefaultConstructibleValue() +{ + struct NonDefaultConstructible + { + explicit NonDefaultConstructible(int v) : value(v) { } + int value = 0; }; - QCOMPARE(runWithPromise(std::cref(funObj), 2).results(), - QList<double>({0, 0})); - // callable with promise - const Callable c{}; - QCOMPARE(runWithPromise(std::cref(c), 2).results(), - QList<double>({0, 0})); + auto future = QtConcurrent::run([] { return NonDefaultConstructible(42); }); + QCOMPARE(future.result().value, 42); +} - // member functions with promise - auto member = &MyObject::member0; - const MyObject obj{}; - QCOMPARE(runWithPromise(std::cref(member), &obj).results(), - QList<double>({0, 2, 1})); +// QTBUG-98901 +void tst_QtConcurrentRun::nullThreadPool() +{ + QThreadPool *pool = nullptr; + std::atomic<bool> isInvoked = false; + auto future = run(pool, [&] { isInvoked = true; }); + future.waitForFinished(); + QVERIFY(future.isCanceled()); + QVERIFY(!isInvoked); +} + +struct LifetimeChecker +{ + LifetimeChecker() { ++count; } + LifetimeChecker(const LifetimeChecker &) { ++count; } + ~LifetimeChecker() { --count; } + + void operator()() { } + + static std::atomic<int> count; +}; +std::atomic<int> LifetimeChecker::count = 0; + +void tst_QtConcurrentRun::nullThreadPoolNoLeak() +{ + { + QThreadPool *pool = nullptr; + auto future = run(pool, LifetimeChecker()); + future.waitForFinished(); + } + QCOMPARE(LifetimeChecker::count, 0); } QTEST_MAIN(tst_QtConcurrentRun) |