QPromise Class

template <typename T> class QPromise

The QPromise class provides a way to store computation results to be accessed by QFuture. More...

Header: #include <QPromise>
CMake: find_package(Qt6 REQUIRED COMPONENTS Core)
target_link_libraries(mytarget PRIVATE Qt6::Core)
qmake: QT += core
Since: Qt 6.0

Note: All functions in this class are thread-safe.

Public Functions

QPromise()
QPromise(QPromise<T> &&other)
~QPromise()
bool addResult(const T &result, int index = -1)
bool addResult(T &&result, int index = -1)
bool addResults(const QList<T> &results)
bool emplaceResult(Args &&... args)
bool emplaceResultAt(int index, Args &&... args)
void finish()
QFuture<T> future() const
bool isCanceled() const
void setException(const QException &e)
void setException(std::exception_ptr e)
void setProgressRange(int minimum, int maximum)
void setProgressValue(int progressValue)
void setProgressValueAndText(int progressValue, const QString &progressText)
void start()
void suspendIfRequested()
void swap(QPromise<T> &other)
QPromise<T> &operator=(QPromise<T> &&other)

Detailed Description

QPromise provides a simple way to communicate progress and results of the user-defined computation to QFuture in an asynchronous fashion. For the communication to work, QFuture must be constructed by QPromise.

You can use QPromise based workloads as an alternative to Qt Concurrent framework when fine-grained control is needed or high-level communication primitive to accompany QFuture is sufficient.

The simplest case of promise and future collaboration would be a single result communication:

    QPromise<int> promise;
    QFuture<int> future = promise.future();

    QScopedPointer<QThread> thread(QThread::create([] (QPromise<int> promise) {
        promise.start();   // notifies QFuture that the computation is started
        promise.addResult(42);
        promise.finish();  // notifies QFuture that the computation is finished
    }, std::move(promise)));
    thread->start();

    future.waitForFinished();  // blocks until QPromise::finish is called
    future.result();  // returns 42

By design, QPromise is a move-only object. This behavior helps to ensure that whenever the promise is destroyed, the associated future object is notified and will not wait forever for the results to become available. However, this is inconvenient if one wants to use the same promise to report results from different threads. There is no specific way to do that at the moment, but known mechanisms exist, such as the use of smart pointers or raw pointers/references. QSharedPointer is a good default choice if you want to copy your promise and use it in multiple places simultaneously. Raw pointers or references are, in a sense, easier, and probably perform better (since there is no need to do a resource management) but may lead to dangling.

Here is an example of how a promise can be used in multiple threads:

    QSharedPointer<QPromise<int>> sharedPromise(new QPromise<int>());
    QFuture<int> future = sharedPromise->future();

    // ...

    sharedPromise->start();

    // here, QPromise is shared between threads via a smart pointer
    QScopedPointer<QThread> threads[] = {
        QScopedPointer<QThread>(QThread::create([] (auto sharedPromise) {
            sharedPromise->addResult(0, 0);  // adds value 0 by index 0
        }, sharedPromise)),
        QScopedPointer<QThread>(QThread::create([] (auto sharedPromise) {
            sharedPromise->addResult(-1, 1);  // adds value -1 by index 1
        }, sharedPromise)),
        QScopedPointer<QThread>(QThread::create([] (auto sharedPromise) {
            sharedPromise->addResult(-2, 2);  // adds value -2 by index 2
        }, sharedPromise)),
        // ...
    };
    // start all threads
    for (auto& t : threads)
        t->start();

    // ...

    future.resultAt(0);  // waits until result at index 0 becomes available. returns value  0
    future.resultAt(1);  // waits until result at index 1 becomes available. returns value -1
    future.resultAt(2);  // waits until result at index 2 becomes available. returns value -2

    sharedPromise->finish();

See also QFuture.

Member Function Documentation

bool QPromise::addResult(T &&result, int index = -1)

bool QPromise::addResult(const T &result, int index = -1)

Same as

emplaceResultAt(index, result);            // first overload
emplaceResultAt(index, std::move(result)); // second overload

or, if index == -1 (the default)

emplaceResult(result);            // first overload
emplaceResult(std::move(result)); // second overload

See also emplaceResultAt(), emplaceResult(), and addResults().

[since 6.6] template <typename Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool>> bool QPromise::emplaceResult(Args &&... args)

[since 6.6] template <typename Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool>> bool QPromise::emplaceResultAt(int index, Args &&... args)

Adds a result constructed from args... to the internal result collection at index position (emplaceResultAt()) or the end of of the collection (emplaceResult()).

Returns true when the result was added to the collection.

Returns false when this promise is in canceled or finished state or when the result was rejected. addResult() rejects to add a result if there's already another result in the collection stored at the same index.

These functions only participate in overload resolutions if T is constructible from args....

You can get a result at a specific index by calling QFuture::resultAt().

Note: It is possible to specify an arbitrary index and request result at that index. However, some QFuture methods operate with continuous results. For instance, iterative approaches that use QFuture::resultCount() or QFuture::const_iterator. In order to get all available results without thinking if there are index gaps or not, use QFuture::results().

This function was introduced in Qt 6.6.

See also addResult() and addResults().

QPromise::QPromise()

Constructs a QPromise with a default state.

QPromise::QPromise(QPromise<T> &&other)

Move constructs a new QPromise from other.

See also operator=().

QPromise::~QPromise()

Destroys the promise.

Note: The promise implicitly transitions to a canceled state on destruction unless finish() is called beforehand by the user.

[since 6.6] bool QPromise::addResults(const QList<T> &results)

Adds results at the end of the internal result collection.

Returns true when results are added to the collection.

Returns false when this promise is in canceled or finished state.

This is more efficient than looping over addResult(), because associated futures will be notified only once per addResults() call, instead of once per element contained in results, as would be the case with individual addResult() calls. But if the calculation of each element takes time, then the code on the receiving end (future) cannot make progress until all results are reported, so use this function only if the calculation of consecutive elements is relatively fast.

This function was introduced in Qt 6.6.

See also addResult().

void QPromise::finish()

Reports that the computation is finished. Once finished, no new results will be added when calling addResult(). This method accompanies start().

See also QFuture::isFinished(), QFuture::waitForFinished(), and start().

QFuture<T> QPromise::future() const

Returns a future associated with this promise.

bool QPromise::isCanceled() const

Returns whether the computation has been canceled with the QFuture::cancel() function. The returned value true indicates that the computation should be finished and finish() called.

Note: After cancellation, results currently available may still be accessed by a future, but new results will not be added when calling addResult().

void QPromise::setException(const QException &e)

Sets exception e to be the result of the computation.

Note: You can set at most one exception throughout the computation execution.

Note: This method must not be used after QFuture::cancel() or finish().

See also isCanceled().

void QPromise::setException(std::exception_ptr e)

This is an overloaded function.

void QPromise::setProgressRange(int minimum, int maximum)

Sets the progress range of the computation to be between minimum and maximum.

If maximum is smaller than minimum, minimum becomes the only legal value.

The progress value is reset to be minimum.

The progress range usage can be disabled by using setProgressRange(0, 0). In this case progress value is also reset to 0.

See also QFuture::progressMinimum(), QFuture::progressMaximum(), and QFuture::progressValue().

void QPromise::setProgressValue(int progressValue)

Sets the progress value of the computation to progressValue. It is possible to only increment the progress value. This is a convenience method for calling setProgressValueAndText(progressValue, QString()).

In case of the progressValue falling out of the progress range, this method has no effect.

See also QFuture::progressValue() and setProgressRange().

void QPromise::setProgressValueAndText(int progressValue, const QString &progressText)

Sets the progress value and the progress text of the computation to progressValue and progressText respectively. It is possible to only increment the progress value.

Note: This function has no effect if the promise is in canceled or finished state.

See also QFuture::progressValue(), QFuture::progressText(), QFuture::cancel(), and finish().

void QPromise::start()

Reports that the computation is started. Calling this method is important to state the beginning of the computation as QFuture methods rely on this information.

Note: Extra attention is required when start() is called from a newly created thread. In such case, the call might naturally be delayed due to the implementation details of the thread scheduling.

See also QFuture::isStarted(), QFuture::waitForFinished(), and finish().

void QPromise::suspendIfRequested()

Conditionally suspends current thread of execution and waits until resumed or canceled by the corresponding methods of QFuture. This method does not block unless the computation is requested to be suspended by QFuture::suspend() or another related method. If you want to check that the execution has been suspended, use QFuture::isSuspended().

Note: When using the same promise in multiple threads, QFuture::isSuspended() becomes true as soon as at least one thread with the promise suspends.

The following code snippets show the usage of suspension mechanism:

    // Create promise and future
    QPromise<int> promise;
    QFuture<int> future = promise.future();

    promise.start();
    // Start a computation thread that supports suspension and cancellation
    QScopedPointer<QThread> thread(QThread::create([] (QPromise<int> promise) {
        for (int i = 0; i < 100; ++i) {
            promise.addResult(i);
            promise.suspendIfRequested();   // support suspension
            if (promise.isCanceled())       // support cancellation
                break;
        }
        promise.finish();
    }, std::move(promise)));
    thread->start();

QFuture::suspend() requests the associated promise to suspend:

    future.suspend();

After QFuture::isSuspended() becomes true, you can get intermediate results:

    future.resultCount();  // returns some number between 0 and 100
    for (int i = 0; i < future.resultCount(); ++i) {
        // process results available before suspension
    }

When suspended, you can resume or cancel the awaiting computation:

    future.resume();  // resumes computation, this call will unblock the promise
    // alternatively, call future.cancel() to stop the computation

    future.waitForFinished();
    future.results();  // returns all computation results - array of values from 0 to 99

See also QFuture::resume(), QFuture::cancel(), QFuture::setSuspended(), and QFuture::toggleSuspended().

[noexcept] void QPromise::swap(QPromise<T> &other)

Swaps promise other with this promise. This operation is very fast and never fails.

[noexcept] QPromise<T> &QPromise::operator=(QPromise<T> &&other)

Move assigns other to this promise and returns a reference to this promise.

© 2024 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.