QtConcurrent: Add documentation for runWithPromise()

Task-number: QTBUG-84702
Change-Id: Ic8233aeffbdbd1420bdbde7ad7d03f25cd438ea8
Reviewed-by: Paul Wicking <paul.wicking@qt.io>
This commit is contained in:
Jarek Kobus 2020-08-20 11:34:38 +02:00
parent 77e04acb4e
commit cba2d04434
6 changed files with 250 additions and 12 deletions

View File

@ -144,3 +144,89 @@ QtConcurrent::run(TestClass(), 42).waitForFinished();
// Ill-formed
QtConcurrent::run(&o, 42).waitForFinished(); // compilation error
//! [8]
//! [9]
extern void aFunction(QPromise<void> &promise);
QFuture<void> future = QtConcurrent::runWithPromise(aFunction);
//! [9]
//! [10]
extern void aFunction(QPromise<void> &promise, int arg1, const QString &arg2);
int integer = ...;
QString string = ...;
QFuture<void> future = QtConcurrent::runWithPromise(aFunction, integer, string);
//! [10]
//! [11]
void helloWorldFunction(QPromise<QString> &promise)
{
promise.addResult("Hello");
promise.addResult("world");
}
QFuture<QString> future = QtConcurrent::runWithPromise(helloWorldFunction);
...
QList<QString> results = future.results();
//! [11]
//! [12]
void aFunction(QPromise<int> &promise)
{
for (int i = 0; i < 100; ++i) {
promise.suspendIfRequested();
if (promise.isCanceled())
return;
// computes the next result, may be time consuming like 1 second
const int res = ... ;
promise.addResult(res);
}
}
QFuture<int> future = QtConcurrent::runWithPromise(aFunction);
... // user pressed a pause button after 10 seconds
future.suspend();
... // user pressed a resume button after 10 seconds
future.resume();
... // user pressed a cancel button after 10 seconds
future.cancel();
//! [12]
//! [13]
void aFunction(QPromise<int> &promise)
{
promise.setProgressRange(0, 100);
int result = 0;
for (int i = 0; i < 100; ++i) {
// computes some part of the task
const int part = ... ;
result += part;
promise.setProgressValue(i);
}
promise.addResult(result);
}
QFutureWatcher<int> watcher;
QObject::connect(&watcher, &QFutureWatcher::progressValueChanged, [](int progress){
... ; // update GUI with a progress
qDebug() << "current progress:" << progress;
});
watcher.setFuture(QtConcurrent::runWithPromise(aFunction));
//! [13]
//! [14]
struct Functor {
void operator()(QPromise<int> &) { }
void operator()(QPromise<double> &) { }
};
Functor f;
runWithPromise<double>(f); // this will select the 2nd overload
// runWithPromise(f); // error, both candidate overloads potentially match
//! [14]

View File

@ -81,10 +81,15 @@
folded into a single result.
\endlist
\li \l {Concurrent Run}
\li \l {Concurrent Run and Run With Promise}
\list
\li \l {QtConcurrent::run}{QtConcurrent::run()} runs a function in
another thread.
\li \l {QtConcurrent::runWithPromise}{QtConcurrent::runWithPromise()}
is like run(), except that the function to run accepts additional
argument of QPromise type that enables more control over the function
execution, like suspending or canceling the execution when requested,
progress reporting or reporting multiple results.
\endlist
\li \l {Concurrent Task}

View File

@ -49,7 +49,7 @@
containing the filtered content, and QtConcurrent::filteredReduced()
returns a single result.
These functions are a part of the \l {Qt Concurrent} framework.
These functions are part of the \l {Qt Concurrent} framework.
Each of the above functions have a blocking variant that returns the final
result instead of a QFuture. You use them in the same way as the

View File

@ -153,7 +153,7 @@
sequence containing the modified content, and QtConcurrent::mappedReduced()
returns a single result.
These functions are a part of the \l {Qt Concurrent} framework.
These functions are part of the \l {Qt Concurrent} framework.
Each of the above functions has a blocking variant that returns
the final result instead of a QFuture. You use them in the same

View File

@ -39,15 +39,27 @@
/*!
\page qtconcurrentrun.html
\title Concurrent Run
\title Concurrent Run and Run With Promise
\ingroup thread
The QtConcurrent::run() function runs a function in a separate thread.
The QtConcurrent::run() and QtConcurrent::runWithPromise()
functions run a function in a separate thread.
The return value of the function is made available through the QFuture API.
The function passed to QtConcurrent::run() is able to report merely
a single computation result to its caller, while the function passed to
QtConcurrent::runWithPromise() can make use of the additional
QPromise API, which enables multiple result reporting, progress reporting,
suspending the computation when requested by the caller, or stopping
the computation on the caller's demand.
This function is a part of the \l {Qt Concurrent} framework.
These functions are part of the Qt Concurrent framework.
\section1 Running a Function in a Separate Thread
\section1 Concurrent Run
The function passed to QtConcurrent::run() may report the result
through its return value.
\section2 Running a Function in a Separate Thread
To run a function in another thread, use QtConcurrent::run():
@ -62,7 +74,7 @@
\snippet code/src_concurrent_qtconcurrentrun.cpp explicit-pool-0
\section1 Passing Arguments to the Function
\section2 Passing Arguments to the Function
Passing arguments to the function is done by adding them to the
QtConcurrent::run() call immediately after the function name. For example:
@ -74,7 +86,7 @@
the function. Changes made to the arguments after calling
QtConcurrent::run() are \e not visible to the thread.
\section1 Returning Values from the Function
\section2 Returning Values from the Function
Any return value from the function is available via QFuture:
@ -88,9 +100,9 @@
to become available. Use QFutureWatcher to get notification when the
function has finished execution and the result is available.
\section1 Additional API Features
\section2 Additional API Features
\section2 Using Member Functions
\section3 Using Member Functions
QtConcurrent::run() also accepts pointers to member functions. The first
argument must be either a const reference or a pointer to an instance of
@ -107,7 +119,7 @@
\snippet code/src_concurrent_qtconcurrentrun.cpp 5
\section2 Using Lambda Functions
\section3 Using Lambda Functions
Calling a lambda function is done like this:
@ -120,6 +132,86 @@
Using callable object is done like this:
\snippet code/src_concurrent_qtconcurrentrun.cpp 8
\section1 Concurrent Run With Promise
The QtConcurrent::runWithPromise() enables more control
for the running task comparing to QtConcurrent::run().
It allows progress reporting of the running task,
reporting multiple results, suspending the execution
if it was requested, or canceling the task on caller's
demand.
\section2 The mandatory QPromise argument
The function passed to QtConcurrent::runWithPromise() is expected
to have an additional argument of \e {QPromise<T> &} type, where
T is the type of the computation result (it should match the type T
of QFuture<T> returned by the QtConcurrent::runWithPromise()), like e.g.:
\snippet code/src_concurrent_qtconcurrentrun.cpp 9
The \e promise argument is instantiated inside the
QtConcurrent::runWithPromise() function, and its reference
is passed to the invoked \e aFunction, so the user
doesn't need to instantiate it by himself, nor pass it explicitly
when calling QtConcurrent::runWithPromise().
The additional argument of QPromise type always needs to appear
as a first argument on function's arguments list, like:
\snippet code/src_concurrent_qtconcurrentrun.cpp 10
\section2 Reporting results
In contrast to QtConcurrent::run(), the function passed to
QtConcurrent::runWithPromise() is expected to always return void type.
Result reporting is done through the additional argument of QPromise type.
It also enables multiple result reporting, like:
\snippet code/src_concurrent_qtconcurrentrun.cpp 11
\section2 Suspending and canceling the execution
The QPromise API also enables suspending and canceling the computation, if requested:
\snippet code/src_concurrent_qtconcurrentrun.cpp 12
The call to \e future.suspend() requests the running task to
hold its execution. After calling this method, the running task
will suspend after the next call to \e promise.suspendIfRequested()
in its iteration loop. In this case the running task will
block on a call to \e promise.suspendIfRequested(). The blocked
call will unblock after the \e future.resume() is called.
Note, that internally suspendIfRequested() uses wait condition
in order to unblock, so the running thread goes into an idle state
instead of wasting its resources when blocked in order to periodically
check if the resume request came from the caller's thread.
The call to \e future.cancel() from the last line causes that the next
call to \e promise.isCanceled() will return \c true and
\e aFunction will return immediately without any further result reporting.
\section2 Progress reporting
It's also possible to report the progress of a task
independently of result reporting, like:
\snippet code/src_concurrent_qtconcurrentrun.cpp 13
The caller installs the \e QFutureWatcher for the \e QFuture
returned by QtConcurrent::runWithPromise() in order to
connect to its \e progressValueChanged() signal and update
e.g. the graphical user interface accordingly.
\section2 Invoking functions with overloaded operator()()
By default, QtConcurrent::runWithPromise() doesn't support functors with
overloaded operator()(). In case of overloaded functors the user
needs to explicitly specify the result type
as a template parameter passed to runWithPromise, like:
\snippet code/src_concurrent_qtconcurrentrun.cpp 14
*/
/*!
@ -172,3 +264,52 @@
\sa {Concurrent Run}
*/
/*!
\since 6.0
\fn QFuture<T> QtConcurrent::runWithPromise(Function function, ...);
Equivalent to
\code
QtConcurrent::runWithPromise(QThreadPool::globalInstance(), function, ...);
\endcode
Runs \a function in a separate thread. The thread is taken from the global
QThreadPool. Note that \a function may not run immediately; \a function
will only be run once a thread becomes available.
The \a function is expected to return void
and must take an additional argument of \e {QPromise<T> &} type,
placed as a first argument in function's argument list. T is the result type
and it is the same for the returned \e QFuture<T>.
Similar to QtConcurrent::run(), the QFuture returned can be used to query for the
running/finished status and the value reported by the function. In addition,
it may be used for suspending or canceling the running task, fetching
multiple results from the called /a function or monitoring progress
reported by the \a function.
\sa {Concurrent Run With Promise}
*/
/*!
\since 6.0
\fn QFuture<T> QtConcurrent::runWithPromise(QThreadPool *pool, Function function, ...);
Runs \a function in a separate thread. The thread is taken from the
QThreadPool \a pool. Note that \a function may not run immediately; \a function
will only be run once a thread becomes available.
The \a function is expected to return void
and must take an additional argument of \e {QPromise<T> &} type,
placed as a first argument in function's argument list. T is the result type
and it is the same for the returned \e QFuture<T>.
Similar to QtConcurrent::run(), the QFuture returned can be used to query for the
running/finished status and the value reported by the function. In addition,
it may be used for suspending or canceling the running task, fetching
multiple results from the called /a function or monitoring progress
reported by the \a function.
\sa {Concurrent Run With Promise}
*/

View File

@ -61,6 +61,12 @@ namespace QtConcurrent {
template <typename T>
QFuture<T> run(QThreadPool *pool, Function function, ...);
template <typename T>
QFuture<T> runWithPromise(Function function, ...);
template <typename T>
QFuture<T> runWithPromise(QThreadPool *pool, Function function, ...);
} // namespace QtConcurrent
#else