Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
src_corelib_thread_qfuture.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
3
4#include <QFuture>
5#include <QtConcurrent>
6#include <QNetworkReply>
7#include <QException>
8#include <QImage>
9#include <iostream>
10
11using namespace std;
12
13class Error : public QException
14{
15public:
16 Error() = default;
17 explicit Error(const QString &message);
18};
19
20template<typename T>
21void handleResult(const QFuture<T> &future);
22
23struct Result {};
24
25//! [10]
26class Object : public QObject
27{
28 Q_OBJECT
29 //...
30signals:
32 void singleArgSignal(int value);
33 void multipleArgs(int value1, double value2, const QString &value3);
34};
35//! [10]
36
37void examples(QFuture<QString> someQStringFuture,
38 QFuture<int> someIntFuture,
39 QFuture<void> someVoidFuture,
40 QObject *someObject,
41 QUrl url)
42{
43 {
44 //! [0]
45 QFuture<QString> future = someQStringFuture;
46
47 QFuture<QString>::const_iterator i;
48 for (i = future.constBegin(); i != future.constEnd(); ++i)
49 cout << qPrintable(*i) << endl;
50 //! [0]
51 }
52
53 {
54 //! [1]
55 QFuture<QString> future;
56 //...
57 QFutureIterator<QString> i(future);
58 while (i.hasNext())
59 QString s = i.next();
60 //! [1]
61 }
62
63 {
64 QFuture<QString> future;
65 //! [2]
66 QFutureIterator<QString> i(future);
67 i.toBack();
68 while (i.hasPrevious())
69 QString s = i.previous();
70 //! [2]
71 }
72
73 {
74 //! [3]
75 using NetworkReply = std::variant<QByteArray, QNetworkReply::NetworkError>;
76
77 enum class IOError { FailedToRead, FailedToWrite };
78 using IOResult = std::variant<QString, IOError>;
79 //! [3]
80
81 //! [4]
82 QFuture<IOResult> future = QtConcurrent::run([url] {
83 //...
84 return NetworkReply(QNetworkReply::TimeoutError);
85 }).then([](NetworkReply reply) {
86 if (auto error = std::get_if<QNetworkReply::NetworkError>(&reply))
87 return IOResult(IOError::FailedToRead);
88
89 auto data = std::get_if<QByteArray>(&reply);
90 // try to write *data and return IOError::FailedToWrite on failure
91 //...
92 });
93
94 auto result = future.result();
95 if (auto filePath = std::get_if<QString>(&result)) {
96 // do something with *filePath
97 }
98 else
99 {
100 // process the error
101 }
102 //! [4]
103 }
104
105 {
106 //! [5]
107 QFuture<int> future = someIntFuture;
108 future.then([](QFuture<int> f) {
109 try {
110 //...
111 auto result = f.result();
112 //...
113 } catch (QException &e) {
114 // handle the exception
115 }
116 }).then([](){/*...*/});
117 //! [5]
118 }
119
120 {
121 //! [6]
122 QFuture<int> future = someIntFuture;
123 auto continuation = future.then([](int res1){ /*...*/ return res1; }).then([](int res2){ /*...*/ return res2; })/*...*/;
124 //...
125 // future throws an exception
126 try {
127 auto result = continuation.result();
128 } catch (QException &e) {
129 // handle the exception
130 }
131 //! [6]
132 }
133
134 {
135 //! [7]
136 QFuture<int> future = someIntFuture;
137 auto resultFuture = future.then([](int res) {
138 //...
139 throw Error();
140 //...
141 return res;
142 }).onFailed([](const Error &e) {
143 // Handle exceptions of type Error
144 //...
145 return -1;
146 }).onFailed([] {
147 // Handle all other types of errors
148 //...
149 return -1;
150 });
151
152 auto result = resultFuture.result(); // result is -1
153 //! [7]
154 }
155
156 {
157 //! [8]
158 QFuture<int> future = someIntFuture;
159 future.then([](int res) {
160 //...
161 throw std::runtime_error("message");
162 //...
163 }).onFailed([](const std::exception &e) {
164 // This handler will be invoked
165 return -1;
166 }).onFailed([](const std::runtime_error &e) {
167 // This handler won't be invoked, because of the handler above.
168 return -1;
169 });
170 //! [8]
171 }
172
173 {
174 //! [9]
175 QFuture<int> future = someIntFuture;
176 auto resultFuture = future.then([](int res) {
177 //...
178 throw Error("message");
179 //...
180 return res;
181 }).onFailed([](const std::exception &e) {
182 // Won't be invoked
183 return -1;
184 }).onFailed([](const QException &e) {
185 // Won't be invoked
186 return -1;
187 });
188
189 try {
190 auto result = resultFuture.result();
191 } catch(QException &someException) {
192 // Handle the exception
193 }
194 //! [9]
195 }
196
197 {
198 //! [11]
199 Object object;
200 QFuture<void> voidFuture = QtFuture::connect(&object, &Object::noArgSignal);
201 QFuture<int> intFuture = QtFuture::connect(&object, &Object::singleArgSignal);
202
203 using Args = std::tuple<int, double, QString>;
204 QFuture<Args> tupleFuture = QtFuture::connect(&object, &Object::multipleArgs);
205 //! [11]
206 }
207
208 {
209 Object object;
210 //! [12]
211 QtFuture::connect(&object, &Object::singleArgSignal).then([](int value) {
212 // do something with the value
213 });
214 //! [12]
215 }
216
217 {
218 Object object;
219 //! [13]
220 QtFuture::connect(&object, &Object::singleArgSignal).then(QtFuture::Launch::Async, [](int value) {
221 // this will run in a new thread
222 });
223 //! [13]
224 }
225
226 {
227 Object object;
228 //! [14]
229 QtFuture::connect(&object, &Object::singleArgSignal).then([](int value) {
230 //...
231 throw std::exception();
232 //...
233 }).onFailed([](const std::exception &e) {
234 // handle the exception
235 }).onFailed([] {
236 // handle other exceptions
237 });
238 //! [14]
239 }
240
241 {
242 //! [15]
243 QFuture<int> testFuture = someIntFuture;
244 auto resultFuture = testFuture.then([](int res) {
245 // Block 1
246 }).onCanceled([] {
247 // Block 2
248 }).onFailed([] {
249 // Block 3
250 }).then([] {
251 // Block 4
252 }).onFailed([] {
253 // Block 5
254 }).onCanceled([] {
255 // Block 6
256 });
257 //! [15]
258 }
259
260 {
261 //! [16]
262 QFuture<int> testFuture = someIntFuture;
263 auto resultFuture = testFuture.then([](int res) {
264 // Block 1
265 }).onFailed([] {
266 // Block 3
267 }).then([] {
268 // Block 4
269 }).onFailed([] {
270 // Block 5
271 }).onCanceled([] {
272 // Block 6
273 });
274 //! [16]
275 }
276
277 {
278 Result result;
279 bool cachedResultsReady;
280
281 //! [20]
282 QObject *context /*...*/;
283 auto future = cachedResultsReady ? QtFuture::makeReadyVoidFuture()
284 : QtConcurrent::run([] { /* compute result */});
285 auto continuation = future.then(context, [] {
286 // Runs in the context's thread
287 }).then([] {
288 // May or may not run in the context's thread
289 });
290 //! [20]
291 }
292
293 {
294 //! [21]
295 QFuture<int> testFuture /*...*/;
296 auto resultFuture = testFuture.then([](int res) {
297 // Block 1
298 //...
299 return 1;
300 }).then([](int res) {
301 // Block 2
302 //...
303 return 2;
304 }).onCanceled([] {
305 // Block 3
306 //...
307 return -1;
308 });
309 //! [21]
310 }
311
312 {
313 //! [22]
314 QList<QFuture<int>> inputFutures {/*...*/};
315
316 // whenAll has type QFuture<QList<QFuture<int>>>
317 auto whenAll = QtFuture::whenAll(inputFutures.begin(), inputFutures.end());
318
319 // whenAllVector has type QFuture<std::vector<QFuture<int>>>
320 auto whenAllVector =
321 QtFuture::whenAll<std::vector<QFuture<int>>>(inputFutures.begin(), inputFutures.end());
322 //! [22]
323 }
324
325 {
326 //! [23]
327 QList<QFuture<int>> inputFutures {/*...*/};
328
329 QtFuture::whenAll(inputFutures.begin(), inputFutures.end())
330 .then([](const QList<QFuture<int>> &results) {
331 for (auto future : results) {
332 if (future.isCanceled())
333 {
334 // handle the cancellation (possibly due to an exception)
335 }
336 else
337 {
338 // do something with the result
339 }
340 }
341 });
342 //! [23]
343 }
344
345 {
346 //! [24]
347 QFuture<int> intFuture /*...*/;
348 QFuture<QString> stringFuture /*...*/;
349 QFuture<void> voidFuture /*...*/;
350
351 using FuturesVariant = std::variant<QFuture<int>, QFuture<QString>, QFuture<void>>;
352
353 // whenAll has type QFuture<QList<FuturesVariant>>
354 auto whenAll = QtFuture::whenAll(intFuture, stringFuture, voidFuture);
355
356 // whenAllVector has type QFuture<std::vector<FuturesVariant>>
357 auto whenAllVector =
358 QtFuture::whenAll<std::vector<FuturesVariant>>(intFuture, stringFuture, voidFuture);
359 //! [24]
360 }
361
362 {
363 //! [25]
364 QFuture<int> intFuture /*...*/;
365 QFuture<QString> stringFuture /*...*/;
366 QFuture<void> voidFuture /*...*/;
367
368 using FuturesVariant = std::variant<QFuture<int>, QFuture<QString>, QFuture<void>>;
369
370 QtFuture::whenAll(intFuture, stringFuture, voidFuture)
371 .then([](const QList<FuturesVariant> &results) {
372 //...
373 for (auto result : results)
374 {
375 // assuming handleResult() is overloaded based on the QFuture type
376 std::visit([](auto &&future) { handleResult(future); }, result);
377 }
378 //...
379 });
380 //! [25]
381 }
382
383 {
384 //! [26]
385 QList<QFuture<int>> inputFutures /*...*/;
386
387 QtFuture::whenAny(inputFutures.begin(), inputFutures.end())
388 .then([](const QtFuture::WhenAnyResult<int> &result) {
389 qsizetype index = result.index;
390 QFuture<int> future = result.future;
391 //...
392 });
393 //! [26]
394 }
395
396 {
397 //! [27]
398 QFuture<int> intFuture /*...*/;
399 QFuture<QString> stringFuture /*...*/;
400 QFuture<void> voidFuture /*...*/;
401
402 using FuturesVariant = std::variant<QFuture<int>, QFuture<QString>, QFuture<void>>;
403
404 QtFuture::whenAny(intFuture, stringFuture, voidFuture).then([](const FuturesVariant &result) {
405 //...
406 // assuming handleResult() is overloaded based on the QFuture type
407 std::visit([](auto &&future) { handleResult(future); }, result);
408 //...
409 });
410 //! [27]
411 }
412
413 {
414 //! [28]
415 QFuture<QFuture<int>> outerFuture /*...*/;
416 QFuture<int> unwrappedFuture = outerFuture.unwrap();
417 //! [28]
418 }
419
420 {
421 auto scale = [](const QImage &img) { return img.scaled(100, 100); };
422 auto reduceImages = [](QImage &result, const QImage &img) { return result; };
423
424 //! [29]
425 auto downloadImages = [] (const QUrl &url) {
426 QList<QImage> images;
427 //...
428 return images;
429 };
430
431 auto processImages = [scale, reduceImages](const QList<QImage> &images) {
432 return QtConcurrent::mappedReduced(images, scale, reduceImages);
433 };
434
435 auto show = [](const QImage &image) { /*...*/ };
436
437 auto future = QtConcurrent::run(downloadImages, url)
438 .then(processImages)
439 .unwrap()
440 .then(show);
441 //! [29]
442 }
443
444 {
445 //! [30]
446 QFuture<QFuture<QFuture<int>>> outerFuture;
447 QFuture<int> unwrappedFuture = outerFuture.unwrap();
448 //! [30]
449 }
450
451 {
452 //! [31]
453 QPromise<int> p;
454
455 QFuture<int> f1 = p.future();
456 f1.then([](int) { qDebug("first"); });
457
458 QFuture<int> f2 = p.future();
459 f2.then([](int) { qDebug("second"); });
460
461 p.start();
462 p.addResult(42);
463 p.finish();
464 //! [31]
465 }
466
467 {
468 //! [32]
469 const std::vector<int> values{1, 2, 3};
470 auto f = QtFuture::makeReadyRangeFuture(values);
471 //! [32]
472 }
473
474 {
475 //! [33]
476 auto f = QtFuture::makeReadyRangeFuture({1, 2, 3});
477 //! [33]
478 }
479
480 {
481 auto f = QtFuture::makeReadyRangeFuture({1, 2, 3});
482 //! [34]
483 const int count = f.resultCount(); // count == 3
484 const auto results = f.results(); // results == { 1, 2, 3 }
485 //! [34]
486 }
487
488 {
489 //! [35]
490 auto f = QtFuture::makeReadyValueFuture(std::make_unique<int>(42));
491 //...
492 const int result = *f.takeResult(); // result == 42
493 //! [35]
494 }
495
496 {
497 //! [36]
498 auto f = QtFuture::makeReadyVoidFuture();
499 //...
500 const bool started = f.isStarted(); // started == true
501 const bool running = f.isRunning(); // running == false
502 const bool finished = f.isFinished(); // finished == true
503 //! [36]
504 }
505
506 {
507 //! [37]
508 QObject *context /*...*/;
509 QFuture<Result> future /*...*/;
510 auto continuation = future.then(context, [context](Result result) {
511 // ...
512 }).onCanceled([context = QPointer(context)] {
513 if (!context)
514 return; // context was destroyed already
515 // handle cancellation
516 });
517
518 //! [37]
519 }
520
521 {
522 //! [38]
523 auto f = QtConcurrent::run([] {/*...*/})
524 .then([]{
525 // Then 1
526 })
527 .then([]{
528 // Then 2
529 })
530 .onCanceled([]{
531 // OnCanceled 1
532 })
533 .then([]{
534 // Then 3
535 })
536 .then([]{
537 // Then 4
538 })
539 .onCanceled([]{
540 // OnCanceled 2
541 });
542 //...
543 f.cancelChain();
544 //! [38]
545 }
546}
547
548class SomeClass : public QObject
549{
551
552public:
554 {
555 {
556 //! [17]
557 // somewhere in the main thread
558 auto future = QtConcurrent::run([] {
559 // This will run in a separate thread
560 //...
561 }).then(this, [] {
562 // Update UI elements
563 });
564 //! [17]
565 }
566
567 {
568 //! [18]
569 auto future = QtConcurrent::run([] {
570 //...
571 }).then(this, [] {
572 // Update UI elements
573 }).then([] {
574 // This will also run in the main thread
575 });
576 //! [18]
577 }
578
579 {
580 //! [19]
581 // somewhere in the main thread
582 auto future = QtConcurrent::run([] {
583 // This will run in a separate thread
584 //...
585 throw std::exception();
586 }).onFailed(this, [] {
587 // Update UI elements
588 });
589 //! [19]
590 }
591
592 }
593};
Error(const QString &message)
Error()=default
void singleArgSignal(int value)
void multipleArgs(int value1, double value2, const QString &value3)
void handleResult(const QFuture< T > &future)
void examples(QFuture< QString > someQStringFuture, QFuture< int > someIntFuture, QFuture< void > someVoidFuture, QObject *someObject, QUrl url)
[10]