diff options
Diffstat (limited to 'src/corelib/thread/qfuture.qdoc')
-rw-r--r-- | src/corelib/thread/qfuture.qdoc | 497 |
1 files changed, 414 insertions, 83 deletions
diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc index e57fe236e8..b278d39882 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,6 +75,15 @@ 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. + 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 @@ -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} */ @@ -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. @@ -617,17 +613,17 @@ Returns a pointer to the current result. */ -/*! \fn template <typename T> bool QFuture<T>::const_iterator::operator!=(const const_iterator &other) const +/*! \fn template <typename T> bool QFuture<T>::const_iterator::operator!=(const const_iterator &lhs, const const_iterator &rhs) - Returns \c true if \a other points to a different result than this iterator; + Returns \c true if \a lhs points to a different result than \a rhs iterator; otherwise returns \c false. \sa operator==() */ -/*! \fn template <typename T> bool QFuture<T>::const_iterator::operator==(const const_iterator &other) const +/*! \fn template <typename T> bool QFuture<T>::const_iterator::operator==(const const_iterator &lhs, const const_iterator &rhs) - Returns \c true if \a other points to the same result as this iterator; + Returns \c true if \a lhs points to the same result as \a rhs iterator; otherwise returns \c false. \sa operator!=() @@ -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 +*/ |