diff --git a/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrenttask.cpp b/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrenttask.cpp index b067b49e7e0..267d6ebc1ef 100644 --- a/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrenttask.cpp +++ b/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrenttask.cpp @@ -129,3 +129,12 @@ QtConcurrent::task([]{ return 42; }).withPriority(10).spawn(); //! [11] QtConcurrent::task([]{ qDebug("Hello, world!"); }).spawn(FutureResult::Ignore); //! [11] + +//! [12] +void increment(QPromise &promise, int i) +{ + promise.addResult(i + 1); +} + +int result = QtConcurrent::task(&increment).withArguments(10).spawn().result(); // result == 11 +//! [12] diff --git a/src/concurrent/qtaskbuilder.h b/src/concurrent/qtaskbuilder.h index e64df242c37..16b21f103b4 100644 --- a/src/concurrent/qtaskbuilder.h +++ b/src/concurrent/qtaskbuilder.h @@ -89,10 +89,11 @@ public: [[nodiscard]] auto spawn() { - return (new StoredFunctionCall(std::move(taskWithArgs))) - ->start(startParameters); + return TaskResolver, std::decay_t...>::run( + std::move(taskWithArgs), startParameters); } + // We don't want to run with promise when we don't return a QFuture void spawn(FutureResult) { (new StoredFunctionCall(std::move(taskWithArgs))) diff --git a/src/concurrent/qtconcurrenttask.qdoc b/src/concurrent/qtconcurrenttask.qdoc index 9000b424fe7..72951f8f117 100644 --- a/src/concurrent/qtconcurrenttask.qdoc +++ b/src/concurrent/qtconcurrenttask.qdoc @@ -148,6 +148,14 @@ QtConcurrent::QTaskBuilder::spawn(QtConcurrent::FutureResult::Ignore): \snippet code/src_concurrent_qtconcurrenttask.cpp 11 + + You can access the promise object associated with the task by defining an + additional argument of \c {QPromise &} type inside the function. + This additional argument must be the first argument passed to the function, and + like in \l {Concurrent Run With Promise} mode, the function is expected to return void type. + Result reporting is done through QPromise API: + + \snippet code/src_concurrent_qtconcurrenttask.cpp 12 */ /*! diff --git a/tests/auto/concurrent/qtconcurrenttask/tst_qtconcurrenttask.cpp b/tests/auto/concurrent/qtconcurrenttask/tst_qtconcurrenttask.cpp index f4e6f996604..3ad34c33693 100644 --- a/tests/auto/concurrent/qtconcurrenttask/tst_qtconcurrenttask.cpp +++ b/tests/auto/concurrent/qtconcurrenttask/tst_qtconcurrenttask.cpp @@ -41,9 +41,11 @@ private Q_SLOTS: void taskWithLambda(); void taskWithArguments(); void useCustomThreadPool(); + void setPriority_data(); void setPriority(); void adjustAllSettings(); void ignoreFutureResult(); + void withPromise(); }; using namespace QtConcurrent; @@ -59,6 +61,7 @@ void tst_QtConcurrentTask::taskWithFreeFunction() QCOMPARE(result, 42); } + void tst_QtConcurrentTask::taskWithClassMethod() { QString result("foobar"); @@ -67,6 +70,7 @@ void tst_QtConcurrentTask::taskWithClassMethod() QCOMPARE(result, "foo"); } + void tst_QtConcurrentTask::taskWithCallableObject() { QCOMPARE(task(std::plus()) @@ -100,8 +104,18 @@ void tst_QtConcurrentTask::useCustomThreadPool() QCOMPARE(result, 42); } +void tst_QtConcurrentTask::setPriority_data() +{ + QTest::addColumn("runWithPromise"); + + QTest::addRow("without promise") << false; + QTest::addRow("with promise") << true; +} + void tst_QtConcurrentTask::setPriority() { + QFETCH(bool, runWithPromise); + QThreadPool pool; pool.setMaxThreadCount(1); @@ -115,15 +129,25 @@ void tst_QtConcurrentTask::setPriority() const int tasksCount = 10; QList priorities(tasksCount); std::iota(priorities.begin(), priorities.end(), 1); - auto seed = std::chrono::system_clock::now().time_since_epoch().count(); + auto seed = std::random_device {}(); std::shuffle(priorities.begin(), priorities.end(), std::default_random_engine(seed)); + qDebug() << "Generated priorities list" << priorities << "using seed" << seed; + QList actual; - for (int priority : priorities) - futureResults << task([priority, &actual] { actual << priority; }) - .onThreadPool(pool) - .withPriority(priority) - .spawn(); + for (int priority : priorities) { + if (runWithPromise) { + futureResults << task([priority, &actual] (QPromise &) { actual << priority; }) + .onThreadPool(pool) + .withPriority(priority) + .spawn(); + } else { + futureResults << task([priority, &actual] { actual << priority; }) + .onThreadPool(pool) + .withPriority(priority) + .spawn(); + } + } sem.release(); pool.waitForDone(); @@ -156,6 +180,7 @@ void tst_QtConcurrentTask::adjustAllSettings() QCOMPARE(result, QList({ 1, 2, 3 })); } + void tst_QtConcurrentTask::ignoreFutureResult() { QThreadPool pool; @@ -171,5 +196,23 @@ void tst_QtConcurrentTask::ignoreFutureResult() QCOMPARE(value, 10); } +void incrementWithPromise(QPromise &promise, int i) +{ + promise.addResult(i + 1); +} + +void return0WithPromise(QPromise &promise) +{ + promise.addResult(0); +} + +void tst_QtConcurrentTask::withPromise() +{ + QCOMPARE(task(&return0WithPromise).spawn().result(), 0); + QCOMPARE(task(&return0WithPromise).withPriority(7).spawn().result(), 0); + QCOMPARE(task(&incrementWithPromise).withArguments(1).spawn().result(), 2); + QCOMPARE(task(&incrementWithPromise).withArguments(1).withPriority(7).spawn().result(), 2); +} + QTEST_MAIN(tst_QtConcurrentTask) #include "tst_qtconcurrenttask.moc"