diff options
Diffstat (limited to 'src/corelib/thread/qfuture.qdoc')
-rw-r--r-- | src/corelib/thread/qfuture.qdoc | 255 |
1 files changed, 193 insertions, 62 deletions
diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc index d52db1c481..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 @@ -133,13 +118,21 @@ 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 + 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} */ @@ -397,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 @@ -412,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 @@ -424,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. @@ -435,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 @@ -451,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 @@ -470,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 @@ -505,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. @@ -513,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. @@ -521,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. @@ -529,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. @@ -620,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!=() @@ -638,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. @@ -650,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. @@ -669,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. */ @@ -943,7 +936,7 @@ \sa QtFuture::whenAny() */ -/*! \fn template<class Sender, class Signal> static QFuture<ArgsType<Signal>> QtFuture::connect(Sender *sender, Signal signal) +/*! \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 @@ -982,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. @@ -996,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. @@ -1016,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. @@ -1035,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) @@ -1055,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) @@ -1080,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) @@ -1179,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() */ @@ -1220,13 +1300,23 @@ 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 @@ -1269,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 @@ -1286,15 +1376,18 @@ 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 @@ -1339,7 +1432,7 @@ \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 @@ -1349,14 +1442,52 @@ 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 |