summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread/qfuture.qdoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/thread/qfuture.qdoc')
-rw-r--r--src/corelib/thread/qfuture.qdoc322
1 files changed, 306 insertions, 16 deletions
diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc
index 076725e19c..8b354fe114 100644
--- a/src/corelib/thread/qfuture.qdoc
+++ b/src/corelib/thread/qfuture.qdoc
@@ -37,14 +37,17 @@
QFuture allows threads to be synchronized against one or more results
which will be ready at a later point in time. The result can be of any type
- that has a default constructor and a copy constructor. If a result is not
- available at the time of calling the result(), resultAt(), or results()
- functions, QFuture will wait until the result becomes available. You can
- use the isResultReadyAt() function to determine if a result is ready or
- not. For QFuture objects that report more than one result, the
- resultCount() function returns the number of continuous results. This
- means that it is always safe to iterate through the results from 0 to
- resultCount().
+ that has default, copy and possibly move constructors. If
+ a result is not available at the time of calling the result(), resultAt(),
+ results(), takeResult(), or takeResults() functions, QFuture
+ will wait until the result becomes available. You can use the isResultReadyAt()
+ function to determine if a result is ready or not. For QFuture objects that
+ report more than one result, the resultCount() function returns the number
+ of continuous results. This means that it is always safe to iterate through
+ the results from 0 to resultCount(). takeResult() and takeResults()
+ invalidate a future and any subsequent attempt to access result or results
+ from the future leads to undefined behavior. isValid() tells you if
+ results can be accessed.
QFuture provides a \l{Java-style iterators}{Java-style iterator}
(QFutureIterator) and an \l{STL-style iterators}{STL-style iterator}
@@ -227,7 +230,7 @@
number of results stored might be different from this value, due to gaps
in the result set. It is always safe to iterate through the results from 0
to resultCount().
- \sa result(), resultAt(), results()
+ \sa result(), resultAt(), results(), takeResult(), takeResults()
*/
/*! \fn template <typename T> int QFuture<T>::progressValue() const
@@ -273,7 +276,10 @@
available, this function will block and wait for the result to become
available. This is a convenience method for calling resultAt(0).
- \sa resultAt(), results()
+ \note Calling result() leads to undefined behavior if isValid()
+ returns \c false for this QFuture.
+
+ \sa resultAt(), results(), takeResult(), takeResults()
*/
/*! \fn template <typename T> T QFuture<T>::resultAt(int index) const
@@ -282,7 +288,10 @@
immediately available, this function will block and wait for the result to
become available.
- \sa result(), results(), resultCount()
+ \note Calling resultAt() leads to undefined behavior if isValid()
+ returns \c false for this QFuture.
+
+ \sa result(), results(), takeResult(), takeResults(), resultCount()
*/
/*! \fn template <typename T> bool QFuture<T>::isResultReadyAt(int index) const
@@ -290,7 +299,10 @@
Returns \c true if the result at \a index is immediately available; otherwise
returns \c false.
- \sa resultAt(), resultCount()
+ \note Calling isResultReadyAt() leads to undefined behavior if isValid()
+ returns \c false for this QFuture.
+
+ \sa resultAt(), resultCount(), takeResult(), takeResults()
*/
/*! \fn template <typename T> QFuture<T>::operator T() const
@@ -300,15 +312,69 @@
available. This is a convenience method for calling result() or
resultAt(0).
- \sa result(), resultAt(), results()
+ \note Calling this function leads to undefined behavior if isValid()
+ returns \c false for this QFuture.
+
+ \sa result(), resultAt(), results(), takeResult(), takeResults(), isValid()
*/
/*! \fn template <typename T> QList<T> QFuture<T>::results() const
- Returns all results from the future. If the results are not immediately
- available, this function will block and wait for them to become available.
+ Returns all results from the future. If the results are not immediately available,
+ this function will block and wait for them to become available.
+
+ \note Calling results() leads to undefined behavior if isValid()
+ returns \c false for this QFuture.
+
+ \sa result(), resultAt(), takeResult(), takeResults(), resultCount(), isValid()
+*/
+
+/*! \fn template <typename T> std::vector<T> QFuture<T>::takeResults()
+
+ If isValid() returns \c false, calling this function leads to undefined behavior.
+ takeResults() takes all results from the QFuture object and invalidates it
+ (isValid() will return \c false for this future). If the results are
+ not immediately available, this function will block and wait for them to
+ become available. This function tries to use move semantics for the results
+ if available and falls back to copy construction if the type is not movable.
- \sa result(), resultAt(), resultCount()
+ \note QFuture in general allows sharing the results between different QFuture
+ objects (and potentially between different threads). takeResults() was introduced
+ to make QFuture also work with move-only types (like std::unique_ptr), so it
+ assumes that only one thread can move the results out of the future, and only
+ once.
+
+ \sa takeResult(), result(), resultAt(), results(), resultCount(), isValid()
+*/
+
+/* \fn template <typename T> std::vector<T> QFuture<T>::takeResult()
+
+ Call this function only if isValid() returns \c true, otherwise
+ the behavior is undefined. This function takes the first result from
+ the QFuture object, for convenience when only one result is expected.
+ If there are any other results, they are discarded after taking the
+ first one (if such behavior is undesired, use takeResults() instead).
+ If the result is not immediately available, this function will block and
+ wait for the result to become available. The QFuture will try to use move
+ semantics if possible, and will fall back to copy construction if the type
+ is not movable. After the result was taken, isValid() will evaluate
+ as \c false.
+
+ \note QFuture in general allows sharing the results between different QFuture
+ objects (and potentially between different threads). takeResult() was introduced
+ to make QFuture also work with move-only types (like std::unique_ptr), so it
+ assumes that only one thread can move the results out of the future, and
+ do it only once.
+
+ \sa takeResults(), result(), results(), resultAt(), isValid()
+*/
+
+/* \fn template <typename T> std::vector<T> QFuture<T>::isValid() const
+
+ Returns true if a result or results can be accessed or taken from this
+ QFuture object. Returns false after the result was taken from the future.
+
+ \sa takeResults(), takeResult(), result(), results(), resultAt()
*/
/*! \fn template <typename T> QFuture<T>::const_iterator QFuture<T>::begin() const
@@ -682,3 +748,227 @@
\sa findNext()
*/
+
+/*!
+ \namespace QtFuture
+
+ \inmodule QtCore
+ \brief Contains miscellaneous identifiers used by the QFuture class.
+*/
+
+
+/*!
+ \enum QtFuture::Launch
+
+ \since 6.0
+
+ Represents execution policies for running a QFuture continuation.
+
+ \value Sync The continuation will be launched in the same thread in
+ which the parent has been executing.
+
+ \value Async The continuation will be launched in in a separate thread taken from
+ the global QThreadPool.
+
+ \value Inherit The continuation will inherit the launch policy of the parent or its
+ thread pool, if it was using a custom one.
+
+ \sa QFuture::then(), QThreadPool::globalInstance()
+
+*/
+
+/*! \fn template<class T> template<class Function> QFuture<typename QFuture<T>::ResultType<Function>> QFuture<T>::then(Function &&function)
+
+ \since 6.0
+ \overload
+
+ Attaches a continuation to this future, allowing to chain multiple asynchronous
+ computations if desired. When the asynchronous computation represented by this
+ future finishes, \a function will be invoked in the same thread in which this
+ future has been running. A new QFuture representing the result of the continuation
+ is returned.
+
+ \note Use other overloads of this method if you need to launch the continuation in
+ a separate thread.
+
+ If this future has a result (is not a QFuture<void>), \a function takes the result
+ of this future as its argument.
+
+ You can chain multiple operations like this:
+
+ \code
+ QFuture<int> future = ...;
+ future.then([](int res1){ ... }).then([](int res2){ ... })...
+ \endcode
+
+ Or:
+ \code
+ QFuture<void> future = ...;
+ future.then([](){ ... }).then([](){ ... })...
+ \endcode
+
+ The continuation can also take a QFuture argument (instead of its value), representing
+ the previous future. This can be useful if, for example, QFuture has multiple results,
+ and the user wants to access them inside the continuation. Or the user needs to handle
+ the exception of the previous future inside the continuation, to not interrupt the chain
+ of multiple continuations. For example:
+
+ \code
+ QFuture<int> future = ...;
+ future.then([](QFuture<int> f) {
+ try {
+ ...
+ auto result = f.result();
+ ...
+ } catch (QException &e) {
+ // handle the exception
+ }
+ }).then(...);
+ \endcode
+
+ If the previous future throws an exception and it is not handled inside the
+ continuation, the exception will be propagated to the continuation future, to
+ allow the caller to handle it:
+
+ \code
+ QFuture<int> parentFuture = ...;
+ auto continuation = parentFuture.then([](int res1){ ... }).then([](int res2){ ... })...
+ ...
+ // parentFuture throws an exception
+ try {
+ auto result = continuation.result();
+ } catch (QException &e) {
+ // handle the exception
+ }
+ \endcode
+
+ In this case the whole chain of continuations will be interrupted.
+
+ \note If the parent future gets canceled, its continuations will
+ also be canceled.
+
+ \sa onFailed()
+*/
+
+/*! \fn template<class T> template<class Function> QFuture<typename QFuture<T>::ResultType<Function>> QFuture<T>::then(QtFuture::Launch policy, Function &&function)
+
+ \since 6.0
+ \overload
+
+ Attaches a continuation to this future, allowing to chain multiple asynchronous
+ computations. When the asynchronous computation represented by this future
+ finishes, \a function will be invoked according to the given launch \a policy.
+ A new QFuture representing the result of the continuation is returned.
+
+ Depending on the \a policy, continuation will run in the same thread as the parent,
+ run in a new thread, or inherit the launch policy and thread pool of the parent.
+
+ In the following example both continuations will run in a new thread (but in
+ the same one).
+
+ \code
+ QFuture<int> future = ...;
+ future.then(QtFuture::Launch::Async, [](int res){ ... }).then([](int res2){ ... });
+ \endcode
+
+ In the following example both continuations will run in new threads using the same
+ thread pool.
+
+ \code
+ QFuture<int> future = ...;
+ future.then(QtFuture::Launch::Async, [](int res){ ... })
+ .then(QtFuture::Launch::Inherit, [](int res2){ ... });
+ \endcode
+
+ \sa onFailed()
+*/
+
+/*! \fn template<class T> template<class Function> QFuture<typename QFuture<T>::ResultType<Function>> QFuture<T>::then(QThreadPool *pool, Function &&function)
+
+ \since 6.0
+ \overload
+
+ Attaches a continuation to this future, allowing to chain multiple asynchronous
+ computations if desired. When the asynchronous computation represented by this
+ future finishes, \a function will be invoked in a separate thread taken from the
+ QThreadPool \a pool.
+
+ \sa onFailed()
+*/
+
+/*! \fn template<class T> template<class Function> QFuture<T> QFuture<T>::onFailed(Function &&handler)
+
+ \since 6.0
+
+ Attaches a failure handler to this future, to handle any exceptions that may
+ have been generated. Returns a QFuture of the parent type. The handler will
+ be invoked only in case of an exception, in the same thread as the parent
+ future has been running. \a handler is a callable which takes either no argument
+ or one argument, to filter by specific error types similar to
+ \l {https://en.cppreference.com/w/cpp/language/try_catch} {catch} statement.
+
+ For example:
+
+ \code
+ QFuture<int> future = ...;
+ auto resultFuture = future.then([](int res) {
+ ...
+ throw Error();
+ ...
+ }).onFailed([](const Error &e) {
+ // Handle exceptions of type Error
+ ...
+ return -1;
+ }).onFailed([] {
+ // Handle all other types of errors
+ ...
+ return -1;
+ });
+
+ auto result = resultFuture.result(); // result is -1
+
+ \endcode
+
+ If there are multiple handlers attached, the first handler that matches with the
+ thrown exception type will be invoked. For example:
+
+ \code
+ QFuture<int> future = ...;
+ future.then([](int res) {
+ ...
+ throw std::runtime_error("message");
+ ...
+ }).onFailed([](const std::exception &e) {
+ // This handler will be invoked
+ }).onFailed([](const std::runtime_error &e) {
+ // This handler won't be invoked, because of the handler above.
+ });
+ \endcode
+
+ If none of the handlers matches with the thrown exception type, the exception
+ will be propagated to the resulted future:
+
+ \code
+ QFuture<int> future = ...;
+ auto resultFuture = future.then([](int res) {
+ ...
+ throw Error("message");
+ ...
+ }).onFailed([](const std::exception &e) {
+ // Won't be invoked
+ }).onFailed([](const QException &e) {
+ // Won't be invoked
+ });
+
+ try {
+ auto result = resultFuture.result();
+ } catch(...) {
+ // Handle the exception
+ }
+ \endcode
+
+ \note You can always attach a handler taking no argument, to handle all exception
+ types and avoid writing the try-catch block.
+
+ \sa then()
+*/