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.qdoc581
1 files changed, 455 insertions, 126 deletions
diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc
index b81944200e..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
@@ -33,8 +9,6 @@
\ingroup thread
- To start a computation, use one of the APIs in the \l {Qt Concurrent} framework.
-
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 default, copy and possibly move constructors. If
@@ -67,7 +41,7 @@
using exceptions. Let's say we want to send a network request to obtain a large
file from a network location. Then we want to write it to the file system and
return its location in case of a success. Both of these operations may fail
- with different errors. So, we use std::variant to keep the result
+ with different errors. So, we use \c std::variant to keep the result
or error:
\snippet code/src_corelib_thread_qfuture.cpp 3
@@ -77,13 +51,13 @@
\snippet code/src_corelib_thread_qfuture.cpp 4
It's possible to chain multiple continuations and handlers in any order.
- The first handler that can handle the state of its parent is invoked first.
- If there's no proper handler, the state is propagated to the next continuation
- or handler. For example:
+ For example:
\snippet code/src_corelib_thread_qfuture.cpp 15
- If \c testFuture is successfully fulfilled \c {Block 1} will be called. If
+ Depending on the state of \c testFuture (canceled, has exception or has a
+ result), the next onCanceled(), onFailed() or then() will be called. So
+ if \c testFuture is successfully fulfilled, \c {Block 1} will be called. If
it succeeds as well, the next then() (\c {Block 4}) is called. If \c testFuture
gets canceled or fails with an exception, either \c {Block 2} or \c {Block 3}
will be called respectively. The next then() will be called afterwards, and the
@@ -101,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
@@ -118,9 +101,6 @@
the isCanceled(), isStarted(), isFinished(), isRunning(), isSuspending()
or isSuspended() functions.
- QFuture is a lightweight reference counted class that can be passed by
- value.
-
QFuture<void> is specialized to not contain any of the result fetching
functions. Any QFuture<T> can be assigned or copied into a QFuture<void>
as well. This is useful if only status or progress information is needed
@@ -128,17 +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.
- \sa QtFuture::connect(), QtFuture::makeReadyFuture(),
+ \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::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
QtFuture::makeExceptionalFuture(), QFutureWatcher, {Qt Concurrent}
*/
@@ -175,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.
@@ -201,8 +195,7 @@
#if QT_DEPRECATED_SINCE(6, 0)
/*! \fn template <typename T> void QFuture<T>::setPaused(bool paused)
- \obsolete
- Use setSuspended() instead.
+ \deprecated [6.0] Use setSuspended() instead.
If \a paused is true, this function pauses the asynchronous computation
represented by the future. If the computation is already paused, this
@@ -218,13 +211,12 @@
returned by QtConcurrent::run() cannot be paused; but the future returned
by QtConcurrent::mappedReduced() can.
- \sa pause(), resume(), togglePaused()
+ \sa suspend(), resume(), toggleSuspended()
*/
/*! \fn template <typename T> bool QFuture<T>::isPaused() const
- \obsolete
- Use isSuspending() or isSuspended() instead.
+ \deprecated [6.0] Use isSuspending() or isSuspended() instead.
Returns \c true if the asynchronous computation has been paused with the
pause() function; otherwise returns \c false.
@@ -233,13 +225,12 @@
function returns \c true. See setPaused() for more details. To check
if pause actually took effect, use isSuspended() instead.
- \sa setPaused(), togglePaused(), isSuspended()
+ \sa toggleSuspended(), isSuspended()
*/
/*! \fn template <typename T> void QFuture<T>::pause()
- \obsolete
- Use suspend() instead.
+ \deprecated [6.0] Use suspend() instead.
Pauses the asynchronous computation represented by this future. This is a
convenience method that simply calls setPaused(true).
@@ -249,15 +240,14 @@
/*! \fn template <typename T> void QFuture<T>::togglePaused()
- \obsolete
- Use toggleSuspended() instead.
+ \deprecated [6.0] Use toggleSuspended() instead.
Toggles the paused state of the asynchronous computation. In other words,
if the computation is currently paused, calling this function resumes it;
if the computation is running, it is paused. This is a convenience method
for calling setPaused(!isPaused()).
- \sa setPaused(), pause(), resume()
+ \sa setSuspended(), suspend(), resume()
*/
#endif // QT_DEPRECATED_SINCE(6, 0)
@@ -400,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
@@ -415,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
@@ -427,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.
@@ -438,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
@@ -454,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
@@ -473,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
@@ -508,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.
@@ -516,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.
@@ -524,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.
@@ -532,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.
@@ -641,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.
@@ -653,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.
@@ -672,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.
*/
@@ -896,22 +886,57 @@
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, or in the thread where
- the parent lives if the continuation is attached after the
- parent has already finished.
+ \value Sync The continuation will be launched in the same thread that
+ fulfills the promise associated with the future to which the
+ continuation was attached, or if it has already finished, the
+ continuation will be invoked immediately, in the thread that
+ executes \c then().
- \value Async The continuation will be launched in in a separate thread taken from
+ \value Async The continuation will be launched 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.
+ \value Inherit The continuation will inherit the launch policy or thread pool of
+ the future to which it is attached.
+
+ \c Sync is used as a default launch policy.
\sa QFuture::then(), QThreadPool::globalInstance()
*/
-/*! \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
@@ -950,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.
@@ -964,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.
@@ -984,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.
@@ -1003,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)
@@ -1023,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)
@@ -1048,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)
@@ -1057,18 +1170,17 @@
\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. If the continuation is attached after the parent has
- already finished, it will be invoked in the thread where the parent lives. This
- method returns a new QFuture representing the result of the continuation.
+ computations if desired, using the \l {QtFuture::Launch}{Sync} policy.
+ \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
@@ -1098,7 +1210,7 @@
In this case the whole chain of continuations will be interrupted.
- \note If the parent future gets canceled, its continuations will
+ \note If this future gets canceled, the continuations attached to it will
also be canceled.
\sa onFailed(), onCanceled()
@@ -1114,10 +1226,12 @@
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.
+ Depending on the \a policy, continuation will be invoked in the same thread as
+ this future, in a new thread, or will inherit the launch policy and thread pool of
+ this future. If no launch policy is specified (see the overload taking only a callable),
+ the \c Sync policy will be used.
- In the following example both continuations will run in a new thread (but in
+ In the following example both continuations will be invoked in a new thread (but in
the same one).
\code
@@ -1125,8 +1239,8 @@
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.
+ In the following example both continuations will be invoked in new threads using the
+ same thread pool.
\code
QFuture<int> future = ...;
@@ -1134,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()
*/
@@ -1144,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()
*/
@@ -1172,10 +1287,11 @@
\snippet code/src_corelib_thread_qfuture.cpp 18
- This is because by default \c .then() is invoked from the same thread as the parent.
+ This is because by default \c .then() is invoked from the same thread as the
+ previous one.
- But note that if the continuation is attached after the parent has already finished,
- it will be invoked in the thread where the parent future lives:
+ But note that if the continuation is attached after this future has already finished,
+ it will be invoked immediately, in the thread that executes \c then():
\snippet code/src_corelib_thread_qfuture.cpp 20
@@ -1184,26 +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 parent type. The handler will
- be invoked only in case of an exception, in the same thread as the parent
- future has been running. If the continuation is attached after the parent has
- already finished, it will be invoked in the thread where the parent lives.
- \a handler is a callable which takes either no argument or one argument, to
- filter by specific error types similar to
+ 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.
+
+ 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.
- For example:
+ 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
@@ -1223,16 +1359,16 @@
\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
- 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 thread of the \a context object.
- This can be useful if the failure needs to be handled in a specific thread.
- For example:
+ Attaches a failure handler to this future, to handle any exceptions that the future
+ raises, or that it has already raised. Returns a QFuture of the same type as this
+ future. The handler will be invoked only in case of an exception, in the thread of
+ the \a context object. This can be useful if the failure needs to be handled in a
+ specific thread. For example:
\snippet code/src_corelib_thread_qfuture.cpp 19
@@ -1240,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 the future is
- canceled. The \a handler is a callable which doesn't take any arguments. It will be
- invoked in the same thread in which this future has been running. If the continuation
- is attached after the parent has already finished, it will be invoked in the thread
- where the parent lives.
+ 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
@@ -1269,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
+*/