summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/thread/qpromise/snippet_qpromise.cpp
blob: 2cef0dca9597572a2f837a5e452539435167070c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

// Note: this file is published under a license that is different from a default
//       test sources license. This is intentional to comply with default
//       snippet license.

#include <QCoreApplication>
#include <QTest>

#include <qfuture.h>
#include <qfuturewatcher.h>
#include <qpromise.h>
#include <qscopedpointer.h>
#include <qsharedpointer.h>

class snippet_QPromise
{
public:
    static void basicExample();
    static void multithreadExample();
    static void suspendExample();
};

void snippet_QPromise::basicExample()
{
#if QT_CONFIG(cxx11_future)
//! [basic]
    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
//! [basic]

    QCOMPARE(future.result(), 42);
    thread->wait();
#endif
}

void snippet_QPromise::multithreadExample()
{
#if QT_CONFIG(cxx11_future)
//! [multithread_init]
    QSharedPointer<QPromise<int>> sharedPromise(new QPromise<int>());
    QFuture<int> future = sharedPromise->future();

    // ...

    sharedPromise->start();
//! [multithread_init]

//! [multithread_main]
    // 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
//! [multithread_main]

    QCOMPARE(future.resultAt(0), 0);
    QCOMPARE(future.resultAt(1), -1);
    QCOMPARE(future.resultAt(2), -2);

    for (auto& t : threads)
        t->wait();
//! [multithread_cleanup]
    sharedPromise->finish();
//! [multithread_cleanup]
#endif
}

void snippet_QPromise::suspendExample()
{
#if QT_CONFIG(cxx11_future)
//! [suspend_start]
    // 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();
//! [suspend_start]

//! [suspend_suspend]
    future.suspend();
//! [suspend_suspend]

    // wait in calling thread until future.isSuspended() becomes true or do
    // something meanwhile
    while (!future.isSuspended()) {
        QThread::msleep(50);
    }

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

    // at least one result is available due to the logic inside a thread
    QVERIFY(future.resultCount() > 0);
    QVERIFY(future.resultCount() <= 100);
    for (int i = 0; i < future.resultCount(); ++i) {
        QCOMPARE(future.resultAt(i), i);
    }

//! [suspend_end]
    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
//! [suspend_end]

    thread->wait();

    QCOMPARE(future.resultCount(), 100);
    QList<int> expected(100);
    std::iota(expected.begin(), expected.end(), 0);
    QCOMPARE(future.results(), expected);
#endif
}