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.qdoc495
1 files changed, 413 insertions, 82 deletions
diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc
index 592e43cddc..9eda766968 100644
--- a/src/corelib/thread/qfuture.qdoc
+++ b/src/corelib/thread/qfuture.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** 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 Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*! \class QFuture
\inmodule QtCore
@@ -99,7 +75,16 @@
If \c testFuture gets canceled, its state is propagated to the next then(),
which will be also canceled. So in this case \c {Block 6} will be called.
- QFuture also offers ways to interact with a runnning computation. For
+ The future can have only one continuation. Consider the following example:
+
+ \snippet code/src_corelib_thread_qfuture.cpp 31
+
+ In this case \c f1 and \c f2 are effectively the same QFuture object, as
+ they share the same internal state. As a result, calling
+ \l {QFuture::}{then} on \c f2 will overwrite the continuation specified for
+ \c {f1}. So, only \c {"second"} will be printed when this code is executed.
+
+ QFuture also offers ways to interact with a running computation. For
instance, the computation can be canceled with the cancel() function. To
suspend or resume the computation, use the setSuspended() function or one of
the suspend(), resume(), or toggleSuspended() convenience functions. Be aware
@@ -123,20 +108,31 @@
To interact with running tasks using signals and slots, use QFutureWatcher.
- You can also use QtFuture::connect to connect signals to a QFuture object
+ You can also use QtFuture::connect() to connect signals to a QFuture object
which will be resolved when a signal is emitted. This allows working with
signals like with QFuture objects. For example, if you combine it with then(),
you can attach multiple continuations to a signal, which are invoked in the
same thread or a new thread.
+ The QtFuture::whenAll() and QtFuture::whenAny() functions can be used to
+ combine several futures and track when the last or first of them completes.
+
A ready QFuture object with a value or a QFuture object holding exception can
- be created using convenience functions QtFuture::makeReadyFuture and
- QtFuture::makeExceptionalFuture.
+ be created using convenience functions QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(), and
+ QtFuture::makeExceptionalFuture().
+
+ \note Some APIs (see \l {QFuture::then()} or various QtConcurrent method
+ overloads) allow scheduling the computation to a specific thread pool.
+ However, QFuture implements a work-stealing algorithm to prevent deadlocks
+ and optimize thread usage. As a result, computations can be executed
+ directly in the thread which requests the QFuture's result.
\note To start a computation and store results in a QFuture, use QPromise or
one of the APIs in the \l {Qt Concurrent} framework.
- \sa QPromise, QtFuture::connect(), QtFuture::makeReadyFuture(),
+ \sa QPromise, QtFuture::connect(), QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
QtFuture::makeExceptionalFuture(), QFutureWatcher, {Qt Concurrent}
*/
@@ -173,8 +169,8 @@
/*! \fn template <typename T> void QFuture<T>::cancel()
Cancels the asynchronous computation represented by this future. Note that
- the cancelation is asynchronous. Use waitForFinished() after calling
- cancel() when you need synchronous cancelation.
+ the cancellation is asynchronous. Use waitForFinished() after calling
+ cancel() when you need synchronous cancellation.
Results currently available may still be accessed on a canceled future,
but new results will \e not become available after calling this function.
@@ -394,7 +390,7 @@
computations), i.e. until isFinished() returns \c true.
*/
-/*! \fn template <typename T> T QFuture<T>::result() const
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> T QFuture<T>::result() const
Returns the first result in the future. If the result is not immediately
available, this function will block and wait for the result to become
@@ -409,7 +405,7 @@
\sa resultAt(), results(), takeResult()
*/
-/*! \fn template <typename T> T QFuture<T>::resultAt(int index) const
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> T QFuture<T>::resultAt(int index) const
Returns the result at \a index in the future. If the result is not
immediately available, this function will block and wait for the result to
@@ -421,7 +417,7 @@
\sa result(), results(), takeResult(), resultCount()
*/
-/*! \fn template <typename T> bool QFuture<T>::isResultReadyAt(int index) const
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> bool QFuture<T>::isResultReadyAt(int index) const
Returns \c true if the result at \a index is immediately available; otherwise
returns \c false.
@@ -432,7 +428,7 @@
\sa resultAt(), resultCount(), takeResult()
*/
-/*! \fn template <typename T> QList<T> QFuture<T>::results() const
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> 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. Note that
@@ -448,7 +444,7 @@
*/
#if 0
-/*! \fn template <typename T> std::vector<T> QFuture<T>::takeResults()
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> 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
@@ -467,7 +463,7 @@
*/
#endif
-/*! \fn template <typename T> std::vector<T> QFuture<T>::takeResult()
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> std::vector<T> QFuture<T>::takeResult()
\since 6.0
@@ -502,7 +498,7 @@
\sa takeResult(), result(), results(), resultAt()
*/
-/*! \fn template <typename T> QFuture<T>::const_iterator QFuture<T>::begin() const
+/*! \fn template<typename T> template<class U = T, typename = QtPrivate::EnableForNonVoid<U>> QFuture<T>::const_iterator QFuture<T>::begin() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first result in the
future.
@@ -510,7 +506,7 @@
\sa constBegin(), end()
*/
-/*! \fn template <typename T> QFuture<T>::const_iterator QFuture<T>::end() const
+/*! \fn template<typename T> template<class U = T, typename = QtPrivate::EnableForNonVoid<U>> QFuture<T>::const_iterator QFuture<T>::end() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary result
after the last result in the future.
@@ -518,7 +514,7 @@
\sa begin(), constEnd()
*/
-/*! \fn template <typename T> QFuture<T>::const_iterator QFuture<T>::constBegin() const
+/*! \fn template<typename T> template<class U = T, typename = QtPrivate::EnableForNonVoid<U>> QFuture<T>::const_iterator QFuture<T>::constBegin() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first result in the
future.
@@ -526,7 +522,7 @@
\sa begin(), constEnd()
*/
-/*! \fn template <typename T> QFuture<T>::const_iterator QFuture<T>::constEnd() const
+/*! \fn template<typename T> template<class U = T, typename = QtPrivate::EnableForNonVoid<U>> QFuture<T>::const_iterator QFuture<T>::constEnd() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary result
after the last result in the future.
@@ -635,7 +631,7 @@
/*! \fn template <typename T> QFuture<T>::const_iterator &QFuture<T>::const_iterator::operator++()
- The prefix ++ operator (\c{++it}) advances the iterator to the next result
+ The prefix \c{++} operator (\c{++it}) advances the iterator to the next result
in the future and returns an iterator to the new current result.
Calling this function on QFuture<T>::constEnd() leads to undefined results.
@@ -647,14 +643,14 @@
\overload
- The postfix ++ operator (\c{it++}) advances the iterator to the next
+ The postfix \c{++} operator (\c{it++}) advances the iterator to the next
result in the future and returns an iterator to the previously current
result.
*/
/*! \fn template <typename T> QFuture<T>::const_iterator &QFuture<T>::const_iterator::operator--()
- The prefix -- operator (\c{--it}) makes the preceding result current and
+ The prefix \c{--} operator (\c{--it}) makes the preceding result current and
returns an iterator to the new current result.
Calling this function on QFuture<T>::constBegin() leads to undefined results.
@@ -666,7 +662,7 @@
\overload
- The postfix -- operator (\c{it--}) makes the preceding result current and
+ The postfix \c{--} operator (\c{it--}) makes the preceding result current and
returns an iterator to the previously current result.
*/
@@ -908,7 +904,39 @@
*/
-/*! \fn template<class Sender, class Signal> static QFuture<ArgsType<Signal>> QtFuture::connect(Sender *sender, Signal signal)
+/*!
+ \class QtFuture::WhenAnyResult
+ \inmodule QtCore
+ \ingroup thread
+ \brief QtFuture::WhenAnyResult is used to represent the result of QtFuture::whenAny().
+ \since 6.3
+
+ The \c {QtFuture::WhenAnyResult<T>} struct is used for packaging the copy and
+ the index of the first completed \c QFuture<T> in the sequence of futures
+ packaging type \c T that are passed to QtFuture::whenAny().
+
+ \sa QFuture, QtFuture::whenAny()
+*/
+
+/*!
+ \variable QtFuture::WhenAnyResult::index
+
+ The field contains the index of the first completed QFuture in the sequence
+ of futures passed to whenAny(). It has type \c qsizetype.
+
+ \sa QtFuture::whenAny()
+*/
+
+/*!
+ \variable QtFuture::WhenAnyResult::future
+
+ The field contains the copy of the first completed QFuture that packages type
+ \c T, where \c T is the type packaged by the futures passed to whenAny().
+
+ \sa QtFuture::whenAny()
+*/
+
+/*! \fn template<class Sender, class Signal, typename = QtPrivate::EnableIfInvocable<Sender, Signal>> static QFuture<ArgsType<Signal>> QtFuture::connect(Sender *sender, Signal signal)
Creates and returns a QFuture which will become available when the \a sender emits
the \a signal. If the \a signal takes no arguments, a QFuture<void> is returned. If
@@ -947,10 +975,11 @@
\sa QFuture, QFuture::then()
*/
-/*! \fn template<typename T> static QFuture<std::decay_t<T>> QtFuture::makeReadyFuture(T &&value)
+/*! \fn template<typename T, typename = QtPrivate::EnableForNonVoid<T>> static QFuture<std::decay_t<T>> QtFuture::makeReadyFuture(T &&value)
\since 6.1
\overload
+ \deprecated [6.6] Use makeReadyValueFuture() instead.
Creates and returns a QFuture which already has a result \a value.
The returned QFuture has a type of std::decay_t<T>, where T is not void.
@@ -961,13 +990,20 @@
const int result = *f.takeResult(); // result == 42
\endcode
- \sa QFuture, QtFuture::makeExceptionalFuture()
+ The method should be avoided because
+ it has an inconsistent set of overloads. From Qt 6.10 onwards, using it
+ in code will result in compiler warnings.
+
+ \sa QFuture, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeExceptionalFuture()
*/
/*! \fn QFuture<void> QtFuture::makeReadyFuture()
\since 6.1
\overload
+ \deprecated [6.6] Use makeReadyVoidFuture() instead.
Creates and returns a void QFuture. Such QFuture can't store any result.
One can use it to query the state of the computation.
@@ -981,14 +1017,21 @@
const bool finished = f.isFinished(); // finished == true
\endcode
+ The method should be avoided because
+ it has an inconsistent set of overloads. From Qt 6.10 onwards, using it
+ in code will result in compiler warnings.
+
\sa QFuture, QFuture::isStarted(), QFuture::isRunning(),
- QFuture::isFinished(), QtFuture::makeExceptionalFuture()
+ QFuture::isFinished(), QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeExceptionalFuture()
*/
/*! \fn template<typename T> static QFuture<T> QtFuture::makeReadyFuture(const QList<T> &values)
\since 6.1
\overload
+ \deprecated [6.6] Use makeReadyRangeFuture() instead.
Creates and returns a QFuture which already has multiple results set from \a values.
@@ -1000,7 +1043,42 @@
const auto results = f.results(); // results == { 1, 2, 3 }
\endcode
- \sa QFuture, QtFuture::makeExceptionalFuture()
+ The method should be avoided because
+ it has an inconsistent set of overloads. From Qt 6.10 onwards, using it
+ in code will result in compiler warnings.
+
+ \sa QFuture, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeExceptionalFuture()
+*/
+
+/*! \fn template<typename T> static QFuture<std::decay_t<T>> QtFuture::makeReadyValueFuture(T &&value)
+
+ \since 6.6
+
+ Creates and returns a QFuture which already has a result \a value.
+ The returned QFuture has a type of std::decay_t<T>, where T is not void.
+ The returned QFuture will already be in the finished state.
+
+ \snippet code/src_corelib_thread_qfuture.cpp 35
+
+ \sa QFuture, QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeReadyVoidFuture(), QtFuture::makeExceptionalFuture()
+*/
+
+/*! \fn QFuture<void> QtFuture::makeReadyVoidFuture()
+
+ \since 6.6
+
+ Creates and returns a void QFuture. Such QFuture can't store any result.
+ One can use it to query the state of the computation.
+ The returned QFuture will already be in the finished state.
+
+ \snippet code/src_corelib_thread_qfuture.cpp 36
+
+ \sa QFuture, QFuture::isStarted(), QFuture::isRunning(),
+ QFuture::isFinished(), QtFuture::makeReadyValueFuture(),
+ QtFuture::makeReadyRangeFuture(), QtFuture::makeExceptionalFuture()
*/
/*! \fn template<typename T> static QFuture<T> QtFuture::makeExceptionalFuture(const QException &exception)
@@ -1020,7 +1098,8 @@
}
\endcode
- \sa QFuture, QException, QtFuture::makeReadyFuture()
+ \sa QFuture, QException, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture()
*/
/*! \fn template<typename T> static QFuture<T> QtFuture::makeExceptionalFuture(std::exception_ptr exception)
@@ -1045,7 +1124,44 @@
}
\endcode
- \sa QFuture, QException, QtFuture::makeReadyFuture()
+ \sa QFuture, QException, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture()
+*/
+
+/*! \fn template<typename Container, QtFuture::if_container_with_input_iterators<Container>> static QFuture<QtFuture::ContainedType<Container>> QtFuture::makeReadyRangeFuture(Container &&container)
+
+ \since 6.6
+ \overload
+
+ Takes an input container \a container and returns a QFuture with multiple
+ results of type \c ContainedType initialized from the values of the
+ \a container.
+
+ \note This overload only participates in overload resolution if the
+ \c Container has input iterators.
+
+ \snippet code/src_corelib_thread_qfuture.cpp 32
+ \dots
+ \snippet code/src_corelib_thread_qfuture.cpp 34
+
+ \sa QFuture, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeExceptionalFuture()
+*/
+
+/*! \fn template<typename ValueType> static QFuture<ValueType> QtFuture::makeReadyRangeFuture(std::initializer_list<ValueType> values)
+
+ \since 6.6
+ \overload
+
+ Returns a QFuture with multiple results of type \c ValueType initialized
+ from the input initializer list \a values.
+
+ \snippet code/src_corelib_thread_qfuture.cpp 33
+ \dots
+ \snippet code/src_corelib_thread_qfuture.cpp 34
+
+ \sa QFuture, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeExceptionalFuture()
*/
/*! \fn template<class T> template<class Function> QFuture<typename QFuture<T>::ResultType<Function>> QFuture<T>::then(Function &&function)
@@ -1055,14 +1171,16 @@
Attaches a continuation to this future, allowing to chain multiple asynchronous
computations if desired, using the \l {QtFuture::Launch}{Sync} policy.
- This method returns a new QFuture representing the result of the continuation.
+ \a function is a callable that takes an argument of the type packaged by this
+ future if this has a result (is not a QFuture<void>). Otherwise it takes no
+ arguments. This method returns a new QFuture that packages a value of the type
+ returned by \a function. The returned future will be in an uninitialized state
+ until the attached continuation is invoked, or until this future fails or is
+ canceled.
\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
@@ -1130,6 +1248,8 @@
.then(QtFuture::Launch::Inherit, [](int res2){ ... });
\endcode
+ See the documentation of the other overload for more details about \a function.
+
\sa onFailed(), onCanceled()
*/
@@ -1140,8 +1260,7 @@
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.
+ future finishes, \a function will be scheduled on \a pool.
\sa onFailed(), onCanceled()
*/
@@ -1181,27 +1300,46 @@
is attached. In this case it will be resolved in the current thread. Therefore, when
in doubt, pass the context explicitly.
+ \target context_lifetime
+ If the \a context is destroyed before the chain has finished, the future is canceled.
+ This implies that a cancellation handler might be invoked when the \a context is not valid
+ anymore. To guard against this, capture the \a context as a QPointer:
+
+ \snippet code/src_corelib_thread_qfuture.cpp 37
+
+ When the context object is destroyed, cancellation happens immediately. Previous futures in the
+ chain are \e {not} cancelled and keep running until they are finished.
+
\note When calling this method, it should be guaranteed that the \a context stays alive
- throughout the execution of the chain.
+ during setup of the chain.
\sa onFailed(), onCanceled()
*/
-/*! \fn template<class T> template<class Function> QFuture<T> QFuture<T>::onFailed(Function &&handler)
+/*! \fn template<class T> template<class Function, typename = std::enable_if_t<!QtPrivate::ArgResolver<Function>::HasExtraArgs>> 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 same type as this future. The
- handler will be invoked only in case of an exception, in the same thread that
- reported that the promise associated with this future is finished with an exception.
- If the handler is attached after this future has already finished, it will be
- invoked immediately, in the thread that executes \c onFailed(). \a handler is a
- callable which takes either no argument or one argument, to filter by specific error
- types, similar to the \l {https://en.cppreference.com/w/cpp/language/try_catch} {catch}
- statement.
+ Attaches a failure handler to this future, to handle any exceptions. The
+ returned future behaves exactly as this future (has the same state and result)
+ unless this future fails with an exception.
- For example:
+ The \a handler is a callable which takes either no argument or one argument, to
+ filter by specific error types, similar to the
+ \l {https://en.cppreference.com/w/cpp/language/try_catch} {catch} statement.
+ It returns a value of the type packaged by this future. After the failure, the
+ returned future packages the value returned by \a handler.
+
+ The handler will only be invoked if an exception is raised. If the exception
+ is raised after this handler is attached, the handler is executed in the thread
+ that reports the future as finished as a result of the exception. If the handler
+ is attached after this future has already failed, it will be invoked immediately,
+ in the thread that executes \c onFailed(). Therefore, the handler cannot always
+ make assumptions about which thread it will be run on. Use the overload that
+ takes a context object if you want to control which thread the handler is
+ invoked on.
+
+ The example below demonstrates how to attach a failure handler:
\snippet code/src_corelib_thread_qfuture.cpp 7
@@ -1221,7 +1359,7 @@
\sa then(), onCanceled()
*/
-/*! \fn template<class T> template<class Function> QFuture<T> QFuture<T>::onFailed(QObject *context, Function &&handler)
+/*! \fn template<class T> template<class Function, typename = std::enable_if_t<!QtPrivate::ArgResolver<Function>::HasExtraArgs>> QFuture<T> QFuture<T>::onFailed(QObject *context, Function &&handler)
\since 6.1
\overload
@@ -1238,26 +1376,63 @@
be invoked from a non-gui thread. So \c this is provided as a context to \c .onFailed(),
to make sure that it will be invoked in the main thread.
+ If the \a context is destroyed before the chain has finished, the future is canceled.
+ See \l {context_lifetime}{then()} for details.
+
\note When calling this method, it should be guaranteed that the \a context stays alive
- throughout the execution of the chain.
+ during setup of the chain.
+
+ See the documentation of the other overload for more details about \a handler.
\sa then(), onCanceled()
*/
-/*! \fn template<class T> template<class Function> QFuture<T> QFuture<T>::onCanceled(Function &&handler)
+/*! \fn template<class T> template<class Function, typename = std::enable_if_t<std::is_invocable_r_v<T, Function>>> QFuture<T> QFuture<T>::onCanceled(Function &&handler)
\since 6.0
- Attaches a cancellation \a handler to this future, to be called when or if the future
- is canceled. The \a handler is a callable which doesn't take any arguments. It will be
- invoked in the same thread that canceled the promise associated with this future. If
- the continuation is attached after this future has already finished, it will be invoked
- immediately, in the thread that executes \c onCanceled().
+ Attaches a cancellation \a handler to this future. The returned future
+ behaves exactly as this future (has the same state and result) unless
+ this future is cancelled. The \a handler is a callable which takes no
+ arguments and returns a value of the type packaged by this future. After
+ cancellation, the returned future packages the value returned by \a handler.
+
+ If attached before the cancellation, \a handler will be invoked in the same
+ thread that reports the future as finished after the cancellation. If the
+ handler is attached after this future has already been canceled, it will be
+ invoked immediately in the thread that executes \c onCanceled(). Therefore,
+ the handler cannot always make assumptions about which thread it will be run
+ on. Use the overload that takes a context object if you want to control
+ which thread the handler is invoked on.
+
+ The example below demonstrates how to attach a cancellation handler:
+
+ \snippet code/src_corelib_thread_qfuture.cpp 21
+
+ If \c testFuture is canceled, \c {Block 3} will be called and the
+ \c resultFuture will have \c -1 as its result. Unlike \c testFuture, it won't
+ be in a \c Canceled state. This means that you can get its result, attach
+ countinuations to it, and so on.
+
+ Also note that you can cancel the chain of continuations while they are
+ executing via the future that started the chain. Let's say \c testFuture.cancel()
+ was called while \c {Block 1} is already executing. The next continuation will
+ detect that cancellation was requested, so \c {Block 2} will be skipped, and
+ the cancellation handler (\c {Block 3}) will be called.
+
+ \note This method returns a new \c QFuture representing the result of the
+ continuation chain. Canceling the resulting \c QFuture itself won't invoke the
+ cancellation handler in the chain that lead to it. This means that if you call
+ \c resultFuture.cancel(), \c {Block 3} won't be called: because \c resultFuture is
+ the future that results from attaching the cancellation handler to \c testFuture,
+ no cancellation handlers have been attached to \c resultFuture itself. Only
+ cancellation of \c testFuture or the futures returned by continuations attached
+ before the \c onCancelled() call can trigger \c{Block 3}.
\sa then(), onFailed()
*/
-/*! \fn template<class T> template<class Function> QFuture<T> QFuture<T>::onCanceled(QObject *context, Function &&handler)
+/*! \fn template<class T> template<class Function, typename = std::enable_if_t<std::is_invocable_r_v<T, Function>>> QFuture<T> QFuture<T>::onCanceled(QObject *context, Function &&handler)
\since 6.1
\overload
@@ -1267,8 +1442,164 @@
invoked in the thread of the \a context object. This can be useful if the cancellation
needs to be handled in a specific thread.
+ If the \a context is destroyed before the chain has finished, the future is canceled.
+ See \l {context_lifetime}{then()} for details.
+
\note When calling this method, it should be guaranteed that the \a context stays alive
- throughout the execution of the chain.
+ during setup of the chain.
+
+ See the documentation of the other overload for more details about \a handler.
\sa then(), onFailed()
*/
+
+/*! \fn template<class T> template<class U> QFuture<U> QFuture<T>::unwrap()
+
+ \since 6.4
+
+ Unwraps the inner future from this \c QFuture<T>, where \c T is a future
+ of type \c QFuture<U>, i.e. this future has type of \c QFuture<QFuture<U>>.
+ For example:
+
+ \snippet code/src_corelib_thread_qfuture.cpp 28
+
+ \c unwrappedFuture will be fulfilled as soon as the inner future nested
+ inside the \c outerFuture is fulfilled, with the same result or exception
+ and in the same thread that reports the inner future as finished. If the
+ inner future is canceled, \c unwrappedFuture will also be canceled.
+
+ This is especially useful when chaining multiple computations, and one of
+ them returns a \c QFuture as its result type. For example, let's say we
+ want to download multiple images from an URL, scale the images, and reduce
+ them to a single image using QtConcurrent::mappedReduced(). We could write
+ something like:
+
+ \snippet code/src_corelib_thread_qfuture.cpp 29
+
+ Here \c QtConcurrent::mappedReduced() returns a \c QFuture<QImage>, so
+ \c .then(processImages) returns a \c QFuture<QFuture<QImage>>. Since
+ \c show() takes a \c QImage as argument, the result of \c .then(processImages)
+ can't be passed to it directly. We need to call \c .unwrap(), that will
+ get the result of the inner future when it's ready and pass it to the next
+ continuation.
+
+ In case of multiple nesting, \c .unwrap() goes down to the innermost level:
+
+ \snippet code/src_corelib_thread_qfuture.cpp 30
+*/
+
+/*! \fn template<typename OutputSequence, typename InputIt> QFuture<OutputSequence> QtFuture::whenAll(InputIt first, InputIt last)
+
+ \since 6.3
+
+ Returns a new QFuture that succeeds when all futures from \a first to \a last
+ complete. \a first and \a last are iterators to a sequence of futures packaging
+ type \c T. \c OutputSequence is a sequence containing all completed futures
+ from \a first to \a last, appearing in the same order as in the input. If the
+ type of \c OutputSequence is not specified, the resulting futures will be
+ returned in a \c QList of \c QFuture<T>. For example:
+
+ \snippet code/src_corelib_thread_qfuture.cpp 22
+
+ \note The output sequence must support random access and the \c resize()
+ operation.
+
+ If \c first equals \c last, this function returns a ready QFuture that
+ contains an empty \c OutputSequence.
+
+//! [whenAll]
+ The returned future always completes successfully after all the specified
+ futures complete. It doesn't matter if any of these futures completes with
+ error or is canceled. You can use \c .then() to process the completed futures
+ after the future returned by \c whenAll() succeeds:
+//! [whenAll]
+
+ \snippet code/src_corelib_thread_qfuture.cpp 23
+
+//! [whenAll-note]
+ \note If the input futures complete on different threads, the future returned
+ by this method will complete in the thread that the last future completes in.
+ Therefore, the continuations attached to the future returned by \c whenAll()
+ cannot always make assumptions about which thread they will be run on. Use the
+ overload of \c .then() that takes a context object if you want to control which
+ thread the continuations are invoked on.
+//! [whenAll-note]
+*/
+
+/*! \fn template<typename OutputSequence, typename... Futures> QFuture<OutputSequence> QtFuture::whenAll(Futures &&... futures)
+
+ \since 6.3
+
+ Returns a new QFuture that succeeds when all \a futures packaging arbitrary
+ types complete. \c OutputSequence is a sequence of completed futures. The type
+ of its entries is \c std::variant<Futures...>. For each \c QFuture<T> passed to
+ \c whenAll(), the entry at the corresponding position in \c OutputSequence
+ will be a \c std::variant holding that \c QFuture<T>, in its completed state.
+ If the type of \c OutputSequence is not specified, the resulting futures will
+ be returned in a QList of \c std::variant<Futures...>. For example:
+
+ \snippet code/src_corelib_thread_qfuture.cpp 24
+
+ \note The output sequence should support random access and the \c resize()
+ operation.
+
+ \include qfuture.qdoc whenAll
+
+ \snippet code/src_corelib_thread_qfuture.cpp 25
+
+ \include qfuture.qdoc whenAll-note
+*/
+
+/*! \fn template<typename T, typename InputIt> QFuture<QtFuture::WhenAnyResult<T>> QtFuture::whenAny(InputIt first, InputIt last)
+
+ \since 6.3
+
+ Returns a new QFuture that succeeds when any of the futures from \a first to
+ \a last completes. \a first and \a last are iterators to a sequence of futures
+ packaging type \c T. The returned future packages a value of type
+ \c {QtFuture::WhenAnyResult<T>} which in turn packages the index of the
+ first completed \c QFuture and the \c QFuture itself. If \a first equals \a last,
+ this function returns a ready \c QFuture that has \c -1 for the \c index field in
+ the QtFuture::WhenAnyResult struct and a default-constructed \c QFuture<T> for
+ the \c future field. Note that a default-constructed QFuture is a completed
+ future in a cancelled state.
+
+//! [whenAny]
+ The returned future always completes successfully after the first future
+ from the specified futures completes. It doesn't matter if the first future
+ completes with error or is canceled. You can use \c .then() to process the
+ result after the future returned by \c whenAny() succeeds:
+//! [whenAny]
+
+ \snippet code/src_corelib_thread_qfuture.cpp 26
+
+//! [whenAny-note]
+ \note If the input futures complete on different threads, the future returned
+ by this method will complete in the thread that the first future completes in.
+ Therefore, the continuations attached to the future returned by \c whenAny()
+ cannot always make assumptions about which thread they will be run on. Use the
+ overload of \c .then() that takes a context object if you want to control which
+ thread the continuations are invoked on.
+//! [whenAny-note]
+
+ \sa QtFuture::WhenAnyResult
+*/
+
+/*! \fn template<typename... Futures> QFuture<std::variant<std::decay_t<Futures>...>> QtFuture::whenAny(Futures &&... futures)
+
+ \since 6.3
+
+ Returns a new QFuture that succeeds when any of the \a futures completes.
+ \a futures can package arbitrary types. The returned future packages the
+ value of type \c std::variant<Futures...> which in turn packages the first
+ completed QFuture from \a futures. You can use
+ \l {https://en.cppreference.com/w/cpp/utility/variant/index} {std::variant::index()}
+ to find out the index of the future in the sequence of \a futures that
+ finished first.
+
+ \include qfuture.qdoc whenAny
+
+ \snippet code/src_corelib_thread_qfuture.cpp 27
+
+ \include qfuture.qdoc whenAny-note
+*/