summaryrefslogtreecommitdiffstats
path: root/src/concurrent
diff options
context:
space:
mode:
authorJarek Kobus <jaroslaw.kobus@qt.io>2020-08-20 11:34:38 +0200
committerJarek Kobus <jaroslaw.kobus@qt.io>2020-08-26 16:37:43 +0200
commitcba2d0443411b937586f259059e7f14c1cf5b512 (patch)
tree1e91b0aa60f2fef5e36d9035a2b55897a56103f6 /src/concurrent
parent77e04acb4e0266d7da2f9e7100ec22836d9889d0 (diff)
QtConcurrent: Add documentation for runWithPromise()
Task-number: QTBUG-84702 Change-Id: Ic8233aeffbdbd1420bdbde7ad7d03f25cd438ea8 Reviewed-by: Paul Wicking <paul.wicking@qt.io>
Diffstat (limited to 'src/concurrent')
-rw-r--r--src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentrun.cpp86
-rw-r--r--src/concurrent/doc/src/qtconcurrent-index.qdoc7
-rw-r--r--src/concurrent/qtconcurrentfilter.cpp2
-rw-r--r--src/concurrent/qtconcurrentmap.cpp2
-rw-r--r--src/concurrent/qtconcurrentrun.cpp159
-rw-r--r--src/concurrent/qtconcurrentrun.h6
6 files changed, 250 insertions, 12 deletions
diff --git a/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentrun.cpp b/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentrun.cpp
index aba64ad94a..60d276cde6 100644
--- a/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentrun.cpp
+++ b/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentrun.cpp
@@ -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]
+
diff --git a/src/concurrent/doc/src/qtconcurrent-index.qdoc b/src/concurrent/doc/src/qtconcurrent-index.qdoc
index cf4711476c..acb516fb63 100644
--- a/src/concurrent/doc/src/qtconcurrent-index.qdoc
+++ b/src/concurrent/doc/src/qtconcurrent-index.qdoc
@@ -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}
diff --git a/src/concurrent/qtconcurrentfilter.cpp b/src/concurrent/qtconcurrentfilter.cpp
index 223aad5b1f..9f4d962518 100644
--- a/src/concurrent/qtconcurrentfilter.cpp
+++ b/src/concurrent/qtconcurrentfilter.cpp
@@ -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
diff --git a/src/concurrent/qtconcurrentmap.cpp b/src/concurrent/qtconcurrentmap.cpp
index 26a4113303..9e5e6aab32 100644
--- a/src/concurrent/qtconcurrentmap.cpp
+++ b/src/concurrent/qtconcurrentmap.cpp
@@ -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
diff --git a/src/concurrent/qtconcurrentrun.cpp b/src/concurrent/qtconcurrentrun.cpp
index c5f2e113a2..fecbb484ff 100644
--- a/src/concurrent/qtconcurrentrun.cpp
+++ b/src/concurrent/qtconcurrentrun.cpp
@@ -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}
+*/
diff --git a/src/concurrent/qtconcurrentrun.h b/src/concurrent/qtconcurrentrun.h
index 2f9b1b5e96..5804393e25 100644
--- a/src/concurrent/qtconcurrentrun.h
+++ b/src/concurrent/qtconcurrentrun.h
@@ -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