QtBase  v6.3.1
tst_qtconcurrentrun.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 #include <qtconcurrentrun.h>
29 #include <QFuture>
30 #include <QMutex>
31 #include <QMutexLocker>
32 #include <QString>
33 #include <QWaitCondition>
34 #include <QTest>
35 #include <QTimer>
36 #include <QFutureSynchronizer>
37 
38 using namespace QtConcurrent;
39 
40 class tst_QtConcurrentRun: public QObject
41 {
42  Q_OBJECT
43 private slots:
44  void runLightFunction();
45  void runHeavyFunction();
46  void returnValue();
47  void reportValueWithPromise();
48  void functionObject();
49  void memberFunctions();
50  void implicitConvertibleTypes();
51  void runWaitLoop();
52  void pollForIsFinished();
53  void recursive();
54 #ifndef QT_NO_EXCEPTIONS
55  void exceptions();
56  void unhandledException();
57 #endif
58  void functor();
59  void lambda();
60  void callableObjectWithState();
61  void withPromise();
62  void withPromiseInThreadPool();
63  void withPromiseAndThen();
64  void moveOnlyType();
65  void crefFunction();
66  void customPromise();
67  void nonDefaultConstructibleValue();
68  void nullThreadPool();
69  void nullThreadPoolNoLeak();
70 };
71 
72 void light()
73 {
74  qDebug("in function");
75  qDebug("done function");
76 }
77 
79 {
80  qDebug("in function");
81  qDebug("done function");
82 }
83 
84 void lightOverloaded(int)
85 {
86  qDebug("in function with arg");
87  qDebug("done function");
88 }
89 
91 {
92  qDebug("in function with promise");
93  qDebug("done function");
94 }
95 
97 {
98  qDebug("in function with promise and with arg");
99  qDebug("done function");
100 }
101 
102 void heavy()
103 {
104  qDebug("in function");
105  QString str;
106  for (int i = 0; i < 1000000; ++i)
107  str.append("a");
108  qDebug("done function");
109 }
110 
111 void tst_QtConcurrentRun::runLightFunction()
112 {
113  qDebug("starting function");
115  qDebug("waiting");
117  qDebug("done");
118 
119  void (*f1)() = lightOverloaded;
120  qDebug("starting function");
121  QFuture<void> future1 = run(f1);
122  qDebug("waiting");
123  future1.waitForFinished();
124  qDebug("done");
125 
126  void (*f2)(int) = lightOverloaded;
127  qDebug("starting function with arg");
128  QFuture<void> future2 = run(f2, 2);
129  qDebug("waiting");
130  future2.waitForFinished();
131  qDebug("done");
132 
134  qDebug("starting function with promise");
135  QFuture<int> future3 = run(f3);
136  qDebug("waiting");
137  future3.waitForFinished();
138  qDebug("done");
139 
140  void (*f4)(QPromise<double> &, int v) = lightOverloaded;
141  qDebug("starting function with promise and with arg");
142  QFuture<double> future4 = run(f4, 2);
143  qDebug("waiting");
144  future4.waitForFinished();
145  qDebug("done");
146 }
147 
148 void tst_QtConcurrentRun::runHeavyFunction()
149 {
151  qDebug("starting function");
153  qDebug("waiting");
155  qDebug("done");
156 }
157 
159 {
160  return 10;
161 }
162 
163 int returnInt1(int i)
164 {
165  return i;
166 }
167 
168 class A
169 {
170 public:
171  int member0() { return 10; }
172  int member1(int in) { return in; }
173 
174  int operator()() { return 10; }
175  int operator()(int in) { return in; }
176 };
177 
178 class AConst
179 {
180 public:
181  int member0() const { return 10; }
182  int member1(int in) const { return in; }
183 
184  int operator()() const { return 10; }
185  int operator()(int in) const { return in; }
186 };
187 
189 {
190 public:
191  int member0() noexcept { return 10; }
192  int member1(int in) noexcept { return in; }
193 
194  int operator()() noexcept { return 10; }
195  int operator()(int in) noexcept { return in; }
196 };
197 
199 {
200 public:
201  int member0() const noexcept { return 10; }
202  int member1(int in) const noexcept { return in; }
203 
204  int operator()() const noexcept { return 10; }
205  int operator()(int in) const noexcept { return in; }
206 };
207 
208 void tst_QtConcurrentRun::returnValue()
209 {
211  QFuture<int> f;
212 
213  f = run(returnInt0);
214  QCOMPARE(f.result(), 10);
215  f = run(&pool, returnInt0);
216  QCOMPARE(f.result(), 10);
217  f = run(returnInt1, 4);
218  QCOMPARE(f.result(), 4);
219  f = run(&pool, returnInt1, 4);
220  QCOMPARE(f.result(), 4);
221 
222 
223  A a;
224  f = run(&A::member0, &a);
225  QCOMPARE(f.result(), 10);
226  f = run(&pool, &A::member0, &a);
227  QCOMPARE(f.result(), 10);
228 
229  f = run(&A::member1, &a, 20);
230  QCOMPARE(f.result(), 20);
231  f = run(&pool, &A::member1, &a, 20);
232  QCOMPARE(f.result(), 20);
233 
234  f = run(&A::member0, a);
235  QCOMPARE(f.result(), 10);
236  f = run(&pool, &A::member0, a);
237  QCOMPARE(f.result(), 10);
238 
239  f = run(&A::member1, a, 20);
240  QCOMPARE(f.result(), 20);
241  f = run(&pool, &A::member1, a, 20);
242  QCOMPARE(f.result(), 20);
243 
244  f = run(a);
245  QCOMPARE(f.result(), 10);
246  f = run(&pool, a);
247  QCOMPARE(f.result(), 10);
248 
249  f = run(a);
250  QCOMPARE(f.result(), 10);
251  f = run(&pool, std::ref(a));
252  QCOMPARE(f.result(), 10);
253 
254  f = run(a, 20);
255  QCOMPARE(f.result(), 20);
256  f = run(&pool, a, 20);
257  QCOMPARE(f.result(), 20);
258 
259  f = run(std::ref(a), 20);
260  QCOMPARE(f.result(), 20);
261  f = run(&pool, std::ref(a), 20);
262  QCOMPARE(f.result(), 20);
263 
264 
265  const AConst aConst = AConst();
266  f = run(&AConst::member0, &aConst);
267  QCOMPARE(f.result(), 10);
268  f = run(&pool, &AConst::member0, &aConst);
269  QCOMPARE(f.result(), 10);
270 
271  f = run(&AConst::member1, &aConst, 20);
272  QCOMPARE(f.result(), 20);
273  f = run(&pool, &AConst::member1, &aConst, 20);
274  QCOMPARE(f.result(), 20);
275 
276  f = run(&AConst::member0, aConst);
277  QCOMPARE(f.result(), 10);
278  f = run(&pool, &AConst::member0, aConst);
279  QCOMPARE(f.result(), 10);
280 
281  f = run(&AConst::member1, aConst, 20);
282  QCOMPARE(f.result(), 20);
283  f = run(&pool, &AConst::member1, aConst, 20);
284  QCOMPARE(f.result(), 20);
285 
286  f = run(aConst);
287  QCOMPARE(f.result(), 10);
288  f = run(&pool, aConst);
289  QCOMPARE(f.result(), 10);
290 
291  f = run(std::ref(a));
292  QCOMPARE(f.result(), 10);
293  f = run(&pool, std::ref(a));
294  QCOMPARE(f.result(), 10);
295 
296  f = run(aConst, 20);
297  QCOMPARE(f.result(), 20);
298  f = run(&pool, aConst, 20);
299  QCOMPARE(f.result(), 20);
300 
301  f = run(std::ref(aConst), 20);
302  QCOMPARE(f.result(), 20);
303  f = run(&pool, std::ref(aConst), 20);
304  QCOMPARE(f.result(), 20);
305 
306 
307  ANoExcept aNoExcept;
308  f = run(&ANoExcept::member0, &aNoExcept);
309  QCOMPARE(f.result(), 10);
310  f = run(&pool, &ANoExcept::member0, &aNoExcept);
311  QCOMPARE(f.result(), 10);
312 
313  f = run(&ANoExcept::member1, &aNoExcept, 20);
314  QCOMPARE(f.result(), 20);
315  f = run(&pool, &ANoExcept::member1, &aNoExcept, 20);
316  QCOMPARE(f.result(), 20);
317 
318  f = run(&ANoExcept::member0, aNoExcept);
319  QCOMPARE(f.result(), 10);
320  f = run(&pool, &ANoExcept::member0, aNoExcept);
321  QCOMPARE(f.result(), 10);
322 
323  f = run(&ANoExcept::member1, aNoExcept, 20);
324  QCOMPARE(f.result(), 20);
325  f = run(&pool, &ANoExcept::member1, aNoExcept, 20);
326  QCOMPARE(f.result(), 20);
327 
328  f = run(aNoExcept);
329  QCOMPARE(f.result(), 10);
330  f = run(&pool, aNoExcept);
331  QCOMPARE(f.result(), 10);
332 
333  f = run(std::ref(aNoExcept));
334  QCOMPARE(f.result(), 10);
335  f = run(&pool, std::ref(aNoExcept));
336  QCOMPARE(f.result(), 10);
337 
338  f = run(aNoExcept, 20);
339  QCOMPARE(f.result(), 20);
340  f = run(&pool, aNoExcept, 20);
341  QCOMPARE(f.result(), 20);
342 
343  f = run(std::ref(aNoExcept), 20);
344  QCOMPARE(f.result(), 20);
345  f = run(&pool, std::ref(aNoExcept), 20);
346  QCOMPARE(f.result(), 20);
347 
348 
349  const AConstNoExcept aConstNoExcept = AConstNoExcept();
350  f = run(&AConstNoExcept::member0, &aConstNoExcept);
351  QCOMPARE(f.result(), 10);
352  f = run(&pool, &AConstNoExcept::member0, &aConstNoExcept);
353  QCOMPARE(f.result(), 10);
354 
355  f = run(&AConstNoExcept::member1, &aConstNoExcept, 20);
356  QCOMPARE(f.result(), 20);
357  f = run(&pool, &AConstNoExcept::member1, &aConstNoExcept, 20);
358  QCOMPARE(f.result(), 20);
359 
360  f = run(&AConstNoExcept::member0, aConstNoExcept);
361  QCOMPARE(f.result(), 10);
362  f = run(&pool, &AConstNoExcept::member0, aConstNoExcept);
363  QCOMPARE(f.result(), 10);
364 
365  f = run(&AConstNoExcept::member1, aConstNoExcept, 20);
366  QCOMPARE(f.result(), 20);
367  f = run(&pool, &AConstNoExcept::member1, aConstNoExcept, 20);
368  QCOMPARE(f.result(), 20);
369 
370  f = run(aConstNoExcept);
371  QCOMPARE(f.result(), 10);
372  f = run(&pool, aConstNoExcept);
373  QCOMPARE(f.result(), 10);
374 
375  f = run(std::ref(aConstNoExcept));
376  QCOMPARE(f.result(), 10);
377  f = run(&pool, std::ref(aConstNoExcept));
378  QCOMPARE(f.result(), 10);
379 
380  f = run(aConstNoExcept, 20);
381  QCOMPARE(f.result(), 20);
382  f = run(&pool, aConstNoExcept, 20);
383  QCOMPARE(f.result(), 20);
384 
385  f = run(std::ref(aConstNoExcept), 20);
386  QCOMPARE(f.result(), 20);
387  f = run(&pool, std::ref(aConstNoExcept), 20);
388  QCOMPARE(f.result(), 20);
389 }
390 
391 void reportInt0(QPromise<int> &promise)
392 {
393  promise.addResult(0);
394 }
395 
396 void reportIntPlusOne(QPromise<int> &promise, int i)
397 {
398  promise.addResult(i + 1);
399 }
400 
402 {
403 public:
404  void member0(QPromise<int> &promise) { promise.addResult(10); }
405  void member1(QPromise<int> &promise, int in) { promise.addResult(in); }
406 
407  void operator()(QPromise<int> &promise) { promise.addResult(10); }
408 };
409 
411 {
412 public:
413  void member0(QPromise<int> &promise) const { promise.addResult(10); }
414  void member1(QPromise<int> &promise, int in) const { promise.addResult(in); }
415 
416  void operator()(QPromise<int> &promise) const { promise.addResult(10); }
417 };
418 
420 {
421 public:
422  void member0(QPromise<int> &promise) noexcept { promise.addResult(10); }
423  void member1(QPromise<int> &promise, int in) noexcept { promise.addResult(in); }
424 
425  void operator()(QPromise<int> &promise) noexcept { promise.addResult(10); }
426 };
427 
429 {
430 public:
431  void member0(QPromise<int> &promise) const noexcept { promise.addResult(10); }
432  void member1(QPromise<int> &promise, int in) const noexcept { promise.addResult(in); }
433 
434  void operator()(QPromise<int> &promise) const noexcept { promise.addResult(10); }
435 };
436 
437 void tst_QtConcurrentRun::reportValueWithPromise()
438 {
440  QFuture<int> f;
441 
442  f = run(reportInt0);
443  QCOMPARE(f.result(), 0);
444  f = run(&pool, reportInt0);
445  QCOMPARE(f.result(), 0);
446  f = run(reportIntPlusOne, 5);
447  QCOMPARE(f.result(), 6);
448  f = run(&pool, reportIntPlusOne, 5);
449  QCOMPARE(f.result(), 6);
450 
451 
452  AWithPromise a;
454  QCOMPARE(f.result(), 10);
455  f = run(&pool, &AWithPromise::member0, &a);
456  QCOMPARE(f.result(), 10);
457 
458  f = run(&AWithPromise::member1, &a, 20);
459  QCOMPARE(f.result(), 20);
460  f = run(&pool, &AWithPromise::member1, &a, 20);
461  QCOMPARE(f.result(), 20);
462 
464  QCOMPARE(f.result(), 10);
466  QCOMPARE(f.result(), 10);
467 
468  f = run(&AWithPromise::member1, a, 20);
469  QCOMPARE(f.result(), 20);
470  f = run(&pool, &AWithPromise::member1, a, 20);
471  QCOMPARE(f.result(), 20);
472 
473  f = run(a);
474  QCOMPARE(f.result(), 10);
475  f = run(&pool, a);
476  QCOMPARE(f.result(), 10);
477 
478  f = run(std::ref(a));
479  QCOMPARE(f.result(), 10);
480  f = run(&pool, std::ref(a));
481  QCOMPARE(f.result(), 10);
482 
483 
484  const AConstWithPromise aConst = AConstWithPromise();
485  f = run(&AConstWithPromise::member0, &aConst);
486  QCOMPARE(f.result(), 10);
487  f = run(&pool, &AConstWithPromise::member0, &aConst);
488  QCOMPARE(f.result(), 10);
489 
490  f = run(&AConstWithPromise::member1, &aConst, 20);
491  QCOMPARE(f.result(), 20);
492  f = run(&pool, &AConstWithPromise::member1, &aConst, 20);
493  QCOMPARE(f.result(), 20);
494 
495  f = run(&AConstWithPromise::member0, aConst);
496  QCOMPARE(f.result(), 10);
497  f = run(&pool, &AConstWithPromise::member0, aConst);
498  QCOMPARE(f.result(), 10);
499 
500  f = run(&AConstWithPromise::member1, aConst, 20);
501  QCOMPARE(f.result(), 20);
502  f = run(&pool, &AConstWithPromise::member1, aConst, 20);
503  QCOMPARE(f.result(), 20);
504 
505  f = run(aConst);
506  QCOMPARE(f.result(), 10);
507  f = run(&pool, aConst);
508  QCOMPARE(f.result(), 10);
509 
510  f = run(std::ref(a));
511  QCOMPARE(f.result(), 10);
512  f = run(&pool, std::ref(a));
513  QCOMPARE(f.result(), 10);
514 
515 
516  ANoExceptWithPromise aNoExcept;
517  f = run(&ANoExceptWithPromise::member0, &aNoExcept);
518  QCOMPARE(f.result(), 10);
519  f = run(&pool, &ANoExceptWithPromise::member0, &aNoExcept);
520  QCOMPARE(f.result(), 10);
521 
522  f = run(&ANoExceptWithPromise::member1, &aNoExcept, 20);
523  QCOMPARE(f.result(), 20);
524  f = run(&pool, &ANoExceptWithPromise::member1, &aNoExcept, 20);
525  QCOMPARE(f.result(), 20);
526 
527  f = run(&ANoExceptWithPromise::member0, aNoExcept);
528  QCOMPARE(f.result(), 10);
529  f = run(&pool, &ANoExceptWithPromise::member0, aNoExcept);
530  QCOMPARE(f.result(), 10);
531 
532  f = run(&ANoExceptWithPromise::member1, aNoExcept, 20);
533  QCOMPARE(f.result(), 20);
534  f = run(&pool, &ANoExceptWithPromise::member1, aNoExcept, 20);
535  QCOMPARE(f.result(), 20);
536 
537  f = run(aNoExcept);
538  QCOMPARE(f.result(), 10);
539  f = run(&pool, aNoExcept);
540  QCOMPARE(f.result(), 10);
541 
542  f = run(std::ref(aNoExcept));
543  QCOMPARE(f.result(), 10);
544  f = run(&pool, std::ref(aNoExcept));
545  QCOMPARE(f.result(), 10);
546 
547 
548  const AConstNoExceptWithPromise aConstNoExcept = AConstNoExceptWithPromise();
549  f = run(&AConstNoExceptWithPromise::member0, &aConstNoExcept);
550  QCOMPARE(f.result(), 10);
551  f = run(&pool, &AConstNoExceptWithPromise::member0, &aConstNoExcept);
552  QCOMPARE(f.result(), 10);
553 
554  f = run(&AConstNoExceptWithPromise::member1, &aConstNoExcept, 20);
555  QCOMPARE(f.result(), 20);
556  f = run(&pool, &AConstNoExceptWithPromise::member1, &aConstNoExcept, 20);
557  QCOMPARE(f.result(), 20);
558 
559  f = run(&AConstNoExceptWithPromise::member0, aConstNoExcept);
560  QCOMPARE(f.result(), 10);
561  f = run(&pool, &AConstNoExceptWithPromise::member0, aConstNoExcept);
562  QCOMPARE(f.result(), 10);
563 
564  f = run(&AConstNoExceptWithPromise::member1, aConstNoExcept, 20);
565  QCOMPARE(f.result(), 20);
566  f = run(&pool, &AConstNoExceptWithPromise::member1, aConstNoExcept, 20);
567  QCOMPARE(f.result(), 20);
568 
569  f = run(aConstNoExcept);
570  QCOMPARE(f.result(), 10);
571  f = run(&pool, aConstNoExcept);
572  QCOMPARE(f.result(), 10);
573 
574  f = run(std::ref(aConstNoExcept));
575  QCOMPARE(f.result(), 10);
576  f = run(&pool, std::ref(aConstNoExcept));
577  QCOMPARE(f.result(), 10);
578 }
579 
580 struct TestClass
581 {
582  void foo() { }
583  void operator()() { }
584  void operator()(int) { }
585  void fooInt(int){ };
586 };
587 
589 {
590  void foo() const { }
591  void operator()() const { }
592  void operator()(int) const { }
593  void fooInt(int) const { };
594 };
595 
596 void tst_QtConcurrentRun::functionObject()
597 {
600  TestClass c;
601 
602  f = run(c);
603  f = run(std::ref(c));
604  f = run(c, 10);
605  f = run(std::ref(c), 10);
606 
607  f = run(&pool, c);
608  f = run(&pool, std::ref(c));
609  f = run(&pool, c, 10);
610  f = run(&pool, std::ref(c), 10);
611 
612  const TestConstClass cc = TestConstClass();
613  f = run(cc);
614  f = run(std::ref(c));
615  f = run(cc, 10);
616  f = run(std::ref(c), 10);
617 
618  f = run(&pool, cc);
619  f = run(&pool, std::ref(c));
620  f = run(&pool, cc, 10);
621  f = run(&pool, std::ref(c), 10);
622 }
623 
624 
625 void tst_QtConcurrentRun::memberFunctions()
626 {
628 
629  TestClass c;
630 
631  run(&TestClass::foo, c).waitForFinished();
632  run(&TestClass::foo, &c).waitForFinished();
633  run(&TestClass::fooInt, c, 10).waitForFinished();
634  run(&TestClass::fooInt, &c, 10).waitForFinished();
635 
636  run(&pool, &TestClass::foo, c).waitForFinished();
637  run(&pool, &TestClass::foo, &c).waitForFinished();
638  run(&pool, &TestClass::fooInt, c, 10).waitForFinished();
639  run(&pool, &TestClass::fooInt, &c, 10).waitForFinished();
640 
641  const TestConstClass cc = TestConstClass();
642  run(&TestConstClass::foo, cc).waitForFinished();
643  run(&TestConstClass::foo, &cc).waitForFinished();
644  run(&TestConstClass::fooInt, cc, 10).waitForFinished();
645  run(&TestConstClass::fooInt, &cc, 10).waitForFinished();
646 
647  run(&pool, &TestConstClass::foo, cc).waitForFinished();
648  run(&pool, &TestConstClass::foo, &cc).waitForFinished();
649  run(&pool, &TestConstClass::fooInt, cc, 10).waitForFinished();
650  run(&pool, &TestConstClass::fooInt, &cc, 10).waitForFinished();
651 }
652 
653 
654 void doubleFunction(double)
655 {
656 
657 }
658 
660 {
661 
662 }
663 
665 {
666 
667 }
668 
670 {
671 
672 }
673 
675 {
676 
677 }
678 
679 
680 void tst_QtConcurrentRun::implicitConvertibleTypes()
681 {
683 
684  double d;
685  run(doubleFunction, d).waitForFinished();
686  run(&pool, doubleFunction, d).waitForFinished();
687  int i;
688  run(doubleFunction, d).waitForFinished();
689  run(&pool, doubleFunction, d).waitForFinished();
690  run(doubleFunction, i).waitForFinished();
691  run(&pool, doubleFunction, i).waitForFinished();
692  run(doubleFunction, 10).waitForFinished();
693  run(&pool, doubleFunction, 10).waitForFinished();
694  run(stringFunction, QLatin1String("Foo")).waitForFinished();
695  run(&pool, stringFunction, QLatin1String("Foo")).waitForFinished();
696  run(stringConstRefFunction, QLatin1String("Foo")).waitForFinished();
697  run(&pool, stringConstRefFunction, QLatin1String("Foo")).waitForFinished();
698  QString string;
699  run(stringRefFunction, std::ref(string)).waitForFinished();
700  run(&pool, stringRefFunction, std::ref(string)).waitForFinished();
701 }
702 
703 void fn() { }
704 
705 void tst_QtConcurrentRun::runWaitLoop()
706 {
707  for (int i = 0; i < 1000; ++i)
708  run(fn).waitForFinished();
709 }
710 
711 static bool allFinished(const QList<QFuture<void> > &futures)
712 {
713  auto hasNotFinished = [](const QFuture<void> &future) { return !future.isFinished(); };
714  return std::find_if(futures.cbegin(), futures.cend(), hasNotFinished)
715  == futures.constEnd();
716 }
717 
718 static void runFunction()
719 {
720  QEventLoop loop;
722  loop.exec();
723 }
724 
725 void tst_QtConcurrentRun::pollForIsFinished()
726 {
727  const int numThreads = std::max(4, 2 * QThread::idealThreadCount());
729 
730  QFutureSynchronizer<void> synchronizer;
731  for (int i = 0; i < numThreads; ++i)
732  synchronizer.addFuture(QtConcurrent::run(&runFunction));
733 
734  // same as synchronizer.waitForFinished() but with a timeout
735  QTRY_VERIFY(allFinished(synchronizer.futures()));
736 }
737 
738 
740 
742 {
743  count.ref();
744  if (--level > 0) {
747  f1.waitForFinished();
748  f2.waitForFinished();
749  }
750 }
751 
753 {
754  count.ref();
755  if (--level > 0) {
758  return f1.result() + f2.result();
759  }
760  return 1;
761 }
762 
763 void tst_QtConcurrentRun::recursive()
764 {
765  int levels = 15;
766 
767  for (int i = 0; i < QThread::idealThreadCount(); ++i) {
768  count.storeRelaxed(0);
771  QCOMPARE(count.loadRelaxed(), (int)std::pow(2.0, levels) - 1);
772  }
773 
774  for (int i = 0; i < QThread::idealThreadCount(); ++i) {
775  count.storeRelaxed(0);
778  QCOMPARE(count.loadRelaxed(), (int)std::pow(2.0, levels) - 1);
779  }
780 }
781 
782 int e;
783 void vfn0()
784 {
785  ++e;
786 }
787 
788 int fn0()
789 {
790  return 1;
791 }
792 
793 void vfn1(double)
794 {
795  ++e;
796 }
797 
798 int fn1(int)
799 {
800  return 1;
801 }
802 
803 void vfn2(double, int *)
804 {
805  ++e;
806 }
807 
808 int fn2(double, int *)
809 {
810  return 1;
811 }
812 
813 
814 #ifndef QT_NO_EXCEPTIONS
816 {
817  throw QException();
818 }
819 
821 {
822  throw QException();
823  return 0;
824 }
825 
826 class SlowTask : public QRunnable
827 {
828 public:
830  void run() override {
831  int iter = 60;
832  while (--iter && !cancel.loadRelaxed())
834  }
835 };
836 
838 
839 void tst_QtConcurrentRun::exceptions()
840 {
842  bool caught;
843 
844  caught = false;
845  try {
846  QtConcurrent::run(throwFunction).waitForFinished();
847  } catch (QException &) {
848  caught = true;
849  }
850  if (!caught)
851  QFAIL("did not get exception");
852 
853  caught = false;
854  try {
855  QtConcurrent::run(&pool, throwFunction).waitForFinished();
856  } catch (QException &) {
857  caught = true;
858  }
859  if (!caught)
860  QFAIL("did not get exception");
861 
862  caught = false;
863  try {
864  QtConcurrent::run(throwFunctionReturn).waitForFinished();
865  } catch (QException &) {
866  caught = true;
867  }
868  if (!caught)
869  QFAIL("did not get exception");
870 
871  caught = false;
872  try {
873  QtConcurrent::run(&pool, throwFunctionReturn).waitForFinished();
874  } catch (QException &) {
875  caught = true;
876  }
877  if (!caught)
878  QFAIL("did not get exception");
879 
880  caught = false;
881  try {
883  } catch (QException &) {
884  caught = true;
885  }
886  QVERIFY2(caught, "did not get exception");
887 
888  // Force the task to be run on this thread.
889  caught = false;
890  QThreadPool shortPool;
891  shortPool.setMaxThreadCount(1);
892  SlowTask *st = new SlowTask();
893  try {
894  shortPool.start(st);
895  QtConcurrent::run(&shortPool, throwFunctionReturn).result();
896  } catch (QException &) {
897  caught = true;
898  }
899 
901 
902  QVERIFY2(caught, "did not get exception");
903 }
904 
905 void tst_QtConcurrentRun::unhandledException()
906 {
907  struct Exception {};
908  bool caught = false;
909  try {
910  auto f = QtConcurrent::run([] { throw Exception {}; });
911  f.waitForFinished();
912  } catch (const QUnhandledException &e) {
913  try {
914  if (e.exception())
915  std::rethrow_exception(e.exception());
916  } catch (const Exception &) {
917  caught = true;
918  }
919  }
920 
921  QVERIFY(caught);
922 }
923 #endif
924 
925 // Compiler supports decltype
926 struct Functor {
927  int operator()() { return 42; }
928  double operator()(double a, double b) { return a/b; }
929  int operator()(int a, int b) { return a/b; }
930  void operator()(int) { }
931  void operator()(int, int, int) { }
932  void operator()(int, int, int, int) { }
933  void operator()(int, int, int, int, int) { }
934  void operator()(int, int, int, int, int, int) { }
935 };
936 
938  void operator()(QPromise<int> &, double) { }
939 };
940 
944  void operator()(QPromise<int> &, int) { }
945  void operator()(QPromise<double> &, int) { }
946 };
947 
948 // This tests functor without result_type; decltype need to be supported by the compiler.
949 void tst_QtConcurrentRun::functor()
950 {
951  Functor f;
952  {
954  QCOMPARE(fut.result(), 42);
955  }
956  {
957  QFuture<double> fut = QtConcurrent::run(f, 8.5, 1.8);
958  QCOMPARE(fut.result(), (8.5/1.8));
959  }
960  {
961  QFuture<int> fut = QtConcurrent::run(f, 19, 3);
962  QCOMPARE(fut.result(), int(19/3));
963  }
964  {
965  QtConcurrent::run(f, 1).waitForFinished();
966  QtConcurrent::run(f, 1,2).waitForFinished();
967  QtConcurrent::run(f, 1,2,3).waitForFinished();
968  QtConcurrent::run(f, 1,2,3,4).waitForFinished();
969  QtConcurrent::run(f, 1,2,3,4,5).waitForFinished();
970  }
971  FunctorWithPromise fWithPromise;
972  {
973  QtConcurrent::run(fWithPromise, 1.5).waitForFinished();
974  }
975  OverloadedFunctorWithPromise ofWithPromise;
976  {
977  QtConcurrent::run<int>(ofWithPromise).waitForFinished();
978  QtConcurrent::run<double>(ofWithPromise).waitForFinished();
979  QtConcurrent::run<int>(ofWithPromise, 1).waitForFinished();
980  QtConcurrent::run<double>(ofWithPromise, 1).waitForFinished();
981  }
982  // and now with explicit pool:
984  {
986  QCOMPARE(fut.result(), 42);
987  }
988  {
989  QFuture<double> fut = QtConcurrent::run(&pool, f, 8.5, 1.8);
990  QCOMPARE(fut.result(), (8.5/1.8));
991  }
992  {
993  QFuture<int> fut = QtConcurrent::run(&pool, f, 19, 3);
994  QCOMPARE(fut.result(), int(19/3));
995  }
996  {
997  QtConcurrent::run(&pool, f, 1).waitForFinished();
998  QtConcurrent::run(&pool, f, 1,2).waitForFinished();
999  QtConcurrent::run(&pool, f, 1,2,3).waitForFinished();
1000  QtConcurrent::run(&pool, f, 1,2,3,4).waitForFinished();
1001  QtConcurrent::run(&pool, f, 1,2,3,4,5).waitForFinished();
1002  }
1003 }
1004 
1005 // Compiler supports lambda
1006 void tst_QtConcurrentRun::lambda()
1007 {
1008  QCOMPARE(QtConcurrent::run([]() { return 45; }).result(), 45);
1009  QCOMPARE(QtConcurrent::run([](int a) { return a+15; }, 12).result(), 12+15);
1010  QCOMPARE(QtConcurrent::run([](int a, double b) { return a + b; }, 12, 15).result(),
1011  double(12+15));
1012  QCOMPARE(QtConcurrent::run([](int a , int, int, int, int b)
1013  { return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5);
1014 
1016  { promise.addResult(45); }).result(), 45);
1017  QCOMPARE(QtConcurrent::run([](QPromise<int> &promise, double input)
1018  { promise.addResult(input / 2.0); }, 15.0).result(), 7);
1019 
1020  {
1021  QString str { "Hello World Foo" };
1022  QFuture<QStringList> f1 = QtConcurrent::run([&](){ return str.split(' '); });
1023  auto r = f1.result();
1024  QCOMPARE(r, QStringList({"Hello", "World", "Foo"}));
1025  }
1026 
1027  // and now with explicit pool:
1028  QThreadPool pool;
1029  QCOMPARE(QtConcurrent::run(&pool, []() { return 45; }).result(), 45);
1030  QCOMPARE(QtConcurrent::run(&pool, [](int a) { return a + 15; }, 12).result(), 12 + 15);
1031  QCOMPARE(QtConcurrent::run(&pool, [](int a, double b)
1032  { return a + b; }, 12, 15).result(), double(12 + 15));
1033  QCOMPARE(QtConcurrent::run(&pool, [](int a , int, int, int, int b)
1034  { return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5);
1035 
1036  {
1037  QString str { "Hello World Foo" };
1038  QFuture<QStringList> f1 = QtConcurrent::run(&pool, [&](){ return str.split(' '); });
1039  auto r = f1.result();
1040  QCOMPARE(r, QStringList({"Hello", "World", "Foo"}));
1041  }
1042 }
1043 
1045 {
1047  int operator()(int newState) { return (state = newState); }
1048 
1049  static constexpr int defaultState() { return 42; }
1050  int state = defaultState();
1051 };
1052 
1054 {
1056  void operator()(QPromise<int> &promise, int newState) { state = newState; promise.addResult(newState); }
1057 
1058  static constexpr int defaultState() { return 42; }
1059  int state = defaultState();
1060 };
1061 
1062 void tst_QtConcurrentRun::callableObjectWithState()
1063 {
1065 
1066  // Run method setNewState explicitly
1069 
1070  // Run operator()(int) explicitly
1071  run(std::ref(o), CallableWithState::defaultState() + 2).waitForFinished();
1073 
1074  // Run on a copy of object (original object remains unchanged)
1075  run(o, CallableWithState::defaultState() + 3).waitForFinished();
1077 
1078  // Explicitly run on a temporary object
1079  QCOMPARE(run(CallableWithState(), 15).result(), 15);
1080 
1081  CallableWithStateWithPromise oWithPromise;
1082 
1083  // Run method setNewState explicitly
1085  CallableWithStateWithPromise::defaultState() + 1).waitForFinished();
1087 
1088  // Run operator()(int) explicitly
1089  run(std::ref(oWithPromise), CallableWithStateWithPromise::defaultState() + 2).waitForFinished();
1091 
1092  // Run on a copy of object (original object remains unchanged)
1093  run(oWithPromise, CallableWithStateWithPromise::defaultState() + 3).waitForFinished();
1095 
1096  // Explicitly run on a temporary object
1098 }
1099 
1100 void report3(QPromise<int> &promise)
1101 {
1102  promise.addResult(0);
1103  promise.addResult(2);
1104  promise.addResult(1);
1105 }
1106 
1107 void reportN(QPromise<double> &promise, int n)
1108 {
1109  for (int i = 0; i < n; ++i)
1110  promise.addResult(0);
1111 }
1112 
1114 {
1115  promise.addResult(s);
1116 }
1117 
1119 {
1120  promise.addResult(s);
1121 }
1122 
1123 class Callable {
1124 public:
1125  void operator()(QPromise<double> &promise, int n) const
1126  {
1127  for (int i = 0; i < n; ++i)
1128  promise.addResult(0);
1129  }
1130 };
1131 
1132 class MyObject {
1133 public:
1134  static void staticMember0(QPromise<double> &promise)
1135  {
1136  promise.addResult(0);
1137  promise.addResult(2);
1138  promise.addResult(1);
1139  }
1140 
1141  static void staticMember1(QPromise<double> &promise, int n)
1142  {
1143  for (int i = 0; i < n; ++i)
1144  promise.addResult(0);
1145  }
1146 
1147  void member0(QPromise<double> &promise) const
1148  {
1149  promise.addResult(0);
1150  promise.addResult(2);
1151  promise.addResult(1);
1152  }
1153 
1154  void member1(QPromise<double> &promise, int n) const
1155  {
1156  for (int i = 0; i < n; ++i)
1157  promise.addResult(0);
1158  }
1159 
1160  void memberString1(QPromise<QString> &promise, const QString &s) const
1161  {
1162  promise.addResult(s);
1163  }
1164 
1166  {
1167  promise.addResult(s);
1168  }
1169 
1171  {
1172  promise.addResult(0);
1173  promise.addResult(2);
1174  promise.addResult(1);
1175  }
1176 };
1177 
1178 void tst_QtConcurrentRun::withPromise()
1179 {
1180  // free function pointer
1182  QList<int>({0, 2, 1}));
1184  QList<int>({0, 2, 1}));
1185 
1186  QCOMPARE(run(reportN, 4).results(),
1187  QList<double>({0, 0, 0, 0}));
1188  QCOMPARE(run(reportN, 2).results(),
1189  QList<double>({0, 0}));
1190 
1191  QString s = QLatin1String("string");
1192  const QString &crs = QLatin1String("cr string");
1193  const QString cs = QLatin1String("c string");
1194 
1196  QList<QString>({s}));
1198  QList<QString>({crs}));
1200  QList<QString>({cs}));
1202  QList<QString>({QString(QLatin1String("rvalue"))}));
1203 
1205  QList<QString>({s}));
1207  QList<QString>({crs}));
1209  QList<QString>({cs}));
1211  QList<QString>({QString(QLatin1String("rvalue"))}));
1212 
1213  // lambda
1214  QCOMPARE(run([](QPromise<double> &promise, int n) {
1215  for (int i = 0; i < n; ++i)
1216  promise.addResult(0);
1217  }, 3).results(),
1218  QList<double>({0, 0, 0}));
1219 
1220  // std::function
1221  const std::function<void(QPromise<double> &, int)> fun = [](QPromise<double> &promise, int n) {
1222  for (int i = 0; i < n; ++i)
1223  promise.addResult(0);
1224  };
1225  QCOMPARE(run(fun, 2).results(),
1226  QList<double>({0, 0}));
1227 
1228  // operator()
1229  QCOMPARE(run(Callable(), 3).results(),
1230  QList<double>({0, 0, 0}));
1231  const Callable c{};
1232  QCOMPARE(run(c, 2).results(),
1233  QList<double>({0, 0}));
1234 
1235  // static member functions
1237  QList<double>({0, 2, 1}));
1239  QList<double>({0, 0}));
1240 
1241  // member functions
1242  const MyObject obj{};
1244  QList<double>({0, 2, 1}));
1246  QList<double>({0, 0, 0, 0}));
1248  QList<QString>({s}));
1250  QList<QString>({crs}));
1252  QList<QString>({cs}));
1254  QList<QString>({QString(QLatin1String("rvalue"))}));
1256  QList<QString>({s}));
1258  QList<QString>({crs}));
1260  QList<QString>({cs}));
1262  QList<QString>({QString(QLatin1String("rvalue"))}));
1263  MyObject nonConstObj{};
1264  QCOMPARE(run(&MyObject::nonConstMember, &nonConstObj).results(),
1265  QList<double>({0, 2, 1}));
1266 }
1267 
1268 void tst_QtConcurrentRun::withPromiseInThreadPool()
1269 {
1271  // free function pointer
1272  QCOMPARE(run(pool.data(), &report3).results(),
1273  QList<int>({0, 2, 1}));
1274  QCOMPARE(run(pool.data(), report3).results(),
1275  QList<int>({0, 2, 1}));
1276 
1277  QCOMPARE(run(pool.data(), reportN, 4).results(),
1278  QList<double>({0, 0, 0, 0}));
1279  QCOMPARE(run(pool.data(), reportN, 2).results(),
1280  QList<double>({0, 0}));
1281 
1282  QString s = QLatin1String("string");
1283  const QString &crs = QLatin1String("cr string");
1284  const QString cs = QLatin1String("c string");
1285 
1286  QCOMPARE(run(pool.data(), reportString1, s).results(),
1287  QList<QString>({s}));
1288  QCOMPARE(run(pool.data(), reportString1, crs).results(),
1289  QList<QString>({crs}));
1290  QCOMPARE(run(pool.data(), reportString1, cs).results(),
1291  QList<QString>({cs}));
1292  QCOMPARE(run(pool.data(), reportString1, QString(QLatin1String("rvalue"))).results(),
1293  QList<QString>({QString(QLatin1String("rvalue"))}));
1294 
1295  QCOMPARE(run(pool.data(), reportString2, s).results(),
1296  QList<QString>({s}));
1297  QCOMPARE(run(pool.data(), reportString2, crs).results(),
1298  QList<QString>({crs}));
1299  QCOMPARE(run(pool.data(), reportString2, cs).results(),
1300  QList<QString>({cs}));
1301  QCOMPARE(run(pool.data(), reportString2, QString(QLatin1String("rvalue"))).results(),
1302  QList<QString>({QString(QLatin1String("rvalue"))}));
1303 
1304  // lambda
1305  QCOMPARE(run(pool.data(), [](QPromise<double> &promise, int n) {
1306  for (int i = 0; i < n; ++i)
1307  promise.addResult(0);
1308  }, 3).results(),
1309  QList<double>({0, 0, 0}));
1310 
1311  // std::function
1312  const std::function<void(QPromise<double> &, int)> fun = [](QPromise<double> &promise, int n) {
1313  for (int i = 0; i < n; ++i)
1314  promise.addResult(0);
1315  };
1316  QCOMPARE(run(pool.data(), fun, 2).results(),
1317  QList<double>({0, 0}));
1318 
1319  // operator()
1320  QCOMPARE(run(pool.data(), Callable(), 3).results(),
1321  QList<double>({0, 0, 0}));
1322  const Callable c{};
1323  QCOMPARE(run(pool.data(), c, 2).results(),
1324  QList<double>({0, 0}));
1325 
1326  // static member functions
1327  QCOMPARE(run(pool.data(), &MyObject::staticMember0).results(),
1328  QList<double>({0, 2, 1}));
1329  QCOMPARE(run(pool.data(), &MyObject::staticMember1, 2).results(),
1330  QList<double>({0, 0}));
1331 
1332  // member functions
1333  const MyObject obj{};
1334  QCOMPARE(run(pool.data(), &MyObject::member0, &obj).results(),
1335  QList<double>({0, 2, 1}));
1336  QCOMPARE(run(pool.data(), &MyObject::member1, &obj, 4).results(),
1337  QList<double>({0, 0, 0, 0}));
1338  QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, s).results(),
1339  QList<QString>({s}));
1340  QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, crs).results(),
1341  QList<QString>({crs}));
1342  QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, cs).results(),
1343  QList<QString>({cs}));
1345  QString(QLatin1String("rvalue"))).results(),
1346  QList<QString>({QString(QLatin1String("rvalue"))}));
1347  QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, s).results(),
1348  QList<QString>({s}));
1349  QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, crs).results(),
1350  QList<QString>({crs}));
1351  QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, cs).results(),
1352  QList<QString>({cs}));
1354  QString(QLatin1String("rvalue"))).results(),
1355  QList<QString>({QString(QLatin1String("rvalue"))}));
1356 }
1357 
1358 void tst_QtConcurrentRun::withPromiseAndThen()
1359 {
1360  bool runExecuted = false;
1361  bool cancelReceivedBeforeSync = false;
1362  bool cancelReceivedAfterSync = false;
1363 
1364  bool syncBegin = false;
1365  bool syncEnd = false;
1366 
1367  QMutex mutex;
1369 
1370  auto reset = [&]() {
1371  runExecuted = false;
1372  cancelReceivedBeforeSync = false;
1373  cancelReceivedAfterSync = false;
1374  syncBegin = false;
1375  syncEnd = false;
1376  };
1377 
1378  auto setFlag = [&mutex, &condition] (bool &flag) {
1379  QMutexLocker locker(&mutex);
1380  flag = true;
1381  condition.wakeOne();
1382  };
1383 
1384  auto waitForFlag = [&mutex, &condition] (const bool &flag) {
1385  QMutexLocker locker(&mutex);
1386  while (!flag)
1387  condition.wait(&mutex);
1388  };
1389 
1390  auto report1WithCancel = [&](QPromise<int> &promise) {
1391  runExecuted = true;
1392  cancelReceivedBeforeSync = promise.isCanceled();
1393 
1394  setFlag(syncBegin);
1395  waitForFlag(syncEnd);
1396 
1397  cancelReceivedAfterSync = promise.isCanceled();
1398  if (cancelReceivedAfterSync)
1399  return;
1400  promise.addResult(1);
1401  };
1402 
1403  {
1404  auto future = run(report1WithCancel);
1405 
1406  waitForFlag(syncBegin);
1407  future.cancel();
1408  setFlag(syncEnd);
1409 
1411  QCOMPARE(future.results().count(), 0);
1412  QVERIFY(runExecuted);
1413  QVERIFY(!cancelReceivedBeforeSync);
1414  QVERIFY(cancelReceivedAfterSync);
1415  }
1416 
1417  reset();
1418 
1419  {
1420  bool thenExecuted = false;
1421  bool cancelExecuted = false;
1422  auto future = run(report1WithCancel);
1423  auto resultFuture = future.then(QtFuture::Launch::Async, [&](int) { thenExecuted = true; })
1424  .onCanceled([&]() { cancelExecuted = true; });
1425 
1426  waitForFlag(syncBegin);
1427  // no cancel this time
1428  setFlag(syncEnd);
1429 
1430  resultFuture.waitForFinished();
1431  QCOMPARE(future.results().count(), 1);
1432  QCOMPARE(future.result(), 1);
1433  QVERIFY(runExecuted);
1434  QVERIFY(thenExecuted);
1435  QVERIFY(!cancelExecuted);
1436  QVERIFY(!cancelReceivedBeforeSync);
1437  QVERIFY(!cancelReceivedAfterSync);
1438  }
1439 
1440  reset();
1441 
1442  {
1443  bool thenExecuted = false;
1444  bool cancelExecuted = false;
1445  auto future = run(report1WithCancel);
1446  auto resultFuture = future.then(QtFuture::Launch::Async, [&](int) { thenExecuted = true; })
1447  .onCanceled([&]() { cancelExecuted = true; });
1448 
1449  waitForFlag(syncBegin);
1450  future.cancel();
1451  setFlag(syncEnd);
1452 
1453  resultFuture.waitForFinished();
1454  QCOMPARE(future.results().count(), 0);
1455  QVERIFY(runExecuted);
1456  QVERIFY(!thenExecuted);
1457  QVERIFY(cancelExecuted);
1458  QVERIFY(!cancelReceivedBeforeSync);
1459  QVERIFY(cancelReceivedAfterSync);
1460  }
1461 }
1462 
1464 {
1465 public:
1466  MoveOnlyType() = default;
1467  MoveOnlyType(const MoveOnlyType &) = delete;
1471 };
1472 
1474 {
1475 public:
1476  void operator()(QPromise<int> &promise, const MoveOnlyType &)
1477  {
1478  promise.addResult(1);
1479  }
1480 };
1481 
1482 void tst_QtConcurrentRun::moveOnlyType()
1483 {
1485  QList<int>({1}));
1486 }
1487 
1488 void tst_QtConcurrentRun::crefFunction()
1489 {
1490  {
1491  // free function pointer with promise
1492  auto fun = &returnInt0;
1493  QCOMPARE(run(std::cref(fun)).result(), 10);
1494 
1495  // lambda with promise
1496  auto lambda = [](int n) {
1497  return 2 * n;
1498  };
1499  QCOMPARE(run(std::cref(lambda), 3).result(), 6);
1500 
1501  // std::function with promise
1502  const std::function<int(int)> funObj = [](int n) {
1503  return 2 * n;
1504  };
1505  QCOMPARE(run(std::cref(funObj), 2).result(), 4);
1506 
1507  // callable with promise
1508  const AConst c{};
1509  QCOMPARE(run(std::cref(c), 2).result(), 2);
1510 
1511  // member functions with promise
1512  auto member = &AConst::member0;
1513  const AConst obj{};
1514  QCOMPARE(run(std::cref(member), &obj).result(), 10);
1515  }
1516 
1517  {
1518  // free function pointer with promise
1519  auto fun = &report3;
1520  QCOMPARE(run(std::cref(fun)).results(),
1521  QList<int>({0, 2, 1}));
1522 
1523  // lambda with promise
1524  auto lambda = [](QPromise<double> &promise, int n) {
1525  for (int i = 0; i < n; ++i)
1526  promise.addResult(0);
1527  };
1528  QCOMPARE(run(std::cref(lambda), 3).results(),
1529  QList<double>({0, 0, 0}));
1530 
1531  // std::function with promise
1532  const std::function<void(QPromise<double> &, int)> funObj =
1533  [](QPromise<double> &promise, int n) {
1534  for (int i = 0; i < n; ++i)
1535  promise.addResult(0);
1536  };
1537  QCOMPARE(run(std::cref(funObj), 2).results(),
1538  QList<double>({0, 0}));
1539 
1540  // callable with promise
1541  const Callable c{};
1542  QCOMPARE(run(std::cref(c), 2).results(),
1543  QList<double>({0, 0}));
1544 
1545  // member functions with promise
1546  auto member = &MyObject::member0;
1547  const MyObject obj{};
1548  QCOMPARE(run(std::cref(member), &obj).results(),
1549  QList<double>({0, 2, 1}));
1550  }
1551 }
1552 
1553 int explicitPromise(QPromise<int> &promise, int &i)
1554 {
1555  promise.setProgressRange(-10, 10);
1556  ++i;
1557  return i * 2;
1558 }
1559 
1560 void tst_QtConcurrentRun::customPromise()
1561 {
1562  QPromise<int> p;
1563  int i = 4;
1565  QCOMPARE(i, 5);
1566  QCOMPARE(p.future().progressMinimum(), -10);
1567  QCOMPARE(p.future().progressMaximum(), 10);
1568 }
1569 
1570 void tst_QtConcurrentRun::nonDefaultConstructibleValue()
1571 {
1572  struct NonDefaultConstructible
1573  {
1574  explicit NonDefaultConstructible(int v) : value(v) { }
1575  int value = 0;
1576  };
1577 
1578  auto future = QtConcurrent::run([] { return NonDefaultConstructible(42); });
1579  QCOMPARE(future.result().value, 42);
1580 }
1581 
1582 // QTBUG-98901
1583 void tst_QtConcurrentRun::nullThreadPool()
1584 {
1585  QThreadPool *pool = nullptr;
1586  std::atomic<bool> isInvoked = false;
1587  auto future = run(pool, [&] { isInvoked = true; });
1590  QVERIFY(!isInvoked);
1591 }
1592 
1594 {
1598 
1599  void operator()() { }
1600 
1601  static std::atomic<int> count;
1602 };
1603 std::atomic<int> LifetimeChecker::count = 0;
1604 
1605 void tst_QtConcurrentRun::nullThreadPoolNoLeak()
1606 {
1607  {
1608  QThreadPool *pool = nullptr;
1609  auto future = run(pool, LifetimeChecker());
1611  }
1613 }
1614 
1616 #include "tst_qtconcurrentrun.moc"
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
int member1(int in) const
int operator()(int in) const
int member0() const
int operator()() const
int member1(int in) const noexcept
int operator()(int in) const noexcept
int member0() const noexcept
int operator()() const noexcept
void operator()(QPromise< int > &promise) const noexcept
void member1(QPromise< int > &promise, int in) const noexcept
void member0(QPromise< int > &promise) const noexcept
void member1(QPromise< int > &promise, int in) const
void operator()(QPromise< int > &promise) const
void member0(QPromise< int > &promise) const
int operator()(int in) noexcept
int operator()() noexcept
int member1(int in) noexcept
int member0() noexcept
void member0(QPromise< int > &promise) noexcept
void member1(QPromise< int > &promise, int in) noexcept
void operator()(QPromise< int > &promise) noexcept
void member0(QPromise< int > &promise)
void operator()(QPromise< int > &promise)
void member1(QPromise< int > &promise, int in)
void operator()(QPromise< double > &promise, int n) const
void operator()(QPromise< int > &promise, const MoveOnlyType &)
MoveOnlyType & operator=(MoveOnlyType &&)=default
MoveOnlyType & operator=(const MoveOnlyType &)=delete
MoveOnlyType()=default
MoveOnlyType(MoveOnlyType &&)=default
MoveOnlyType(const MoveOnlyType &)=delete
[0]
Definition: myobject.h:58
void member0(QPromise< double > &promise) const
void memberString2(QPromise< QString > &promise, QString s) const
static void staticMember0(QPromise< double > &promise)
static void staticMember1(QPromise< double > &promise, int n)
void member1(QPromise< double > &promise, int n) const
void nonConstMember(QPromise< double > &promise)
void memberString1(QPromise< QString > &promise, const QString &s) const
The QAtomicInt class provides platform-independent atomic operations on int.
Definition: qatomic.h:158
void storeRelaxed(T newValue) noexcept
Definition: qbasicatomic.h:91
The QEventLoop class provides a means of entering and leaving an event loop.
Definition: qeventloop.h:50
int exec(ProcessEventsFlags flags=AllEvents)
Definition: qeventloop.cpp:162
void quit()
Definition: qeventloop.cpp:329
The QException class provides a base class for exceptions that can be transferred across threads.
Definition: qexception.h:58
bool isCanceled() const
Definition: qfuture.h:101
void cancel()
Definition: qfuture.h:100
QList< T > results() const
Definition: qfuture.h:150
T result() const
Definition: qfuture.h:331
void waitForFinished()
Definition: qfuture.h:138
QFuture< ResultType< Function > > then(Function &&function)
bool isFinished() const
Definition: qfuture.h:130
void addFuture(const QFuture< T > &future)
QList< QFuture< T > > futures() const
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
Definition: qlist.h:108
The QMutex class provides access serialization between threads.
Definition: qmutex.h:285
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes.
Definition: qmutex.h:317
bool isCanceled() const
Definition: qpromise.h:102
void setProgressRange(int minimum, int maximum)
Definition: qpromise.h:105
bool addResult(U &&result, int index=-1)
Definition: qpromise.h:85
The QRunnable class is the base class for all runnable objects.
Definition: qrunnable.h:49
The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon dest...
The QString class provides a Unicode character string.
Definition: qstring.h:388
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:7672
QString & append(QChar c)
Definition: qstring.cpp:3152
static int idealThreadCount() noexcept
Definition: qthread.cpp:884
static QThread * currentThread()
Definition: qthread.cpp:879
static void msleep(unsigned long)
The QThreadPool class manages a collection of QThreads.
Definition: qthreadpool.h:56
void start(QRunnable *runnable, int priority=0)
static QThreadPool * globalInstance()
void setMaxThreadCount(int maxThreadCount)
bool singleShot
whether the timer is a single-shot timer
Definition: qtimer.h:60
The QUnhandledException class represents an unhandled exception in a Qt Concurrent worker thread.
Definition: qexception.h:67
static QAtomicInt cancel
void run() override
QString str
[2]
QCOMPARE(spy.count(), 1)
else opt state
[0]
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
auto it unsigned count const
Definition: hb-iter.hh:848
The QtConcurrent namespace provides high-level APIs that make it possible to write multi-threaded pro...
Definition: qtaskbuilder.h:81
auto run(QThreadPool *pool, Function &&f, Args &&...args)
#define QString()
Definition: parse-defines.h:51
void
Definition: png.h:1080
QList< QString > QStringList
Definition: qcontainerfwd.h:64
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
EGLOutputLayerEXT EGLint EGLAttrib value
#define qDebug
[1]
Definition: qlogging.h:177
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLenum GLuint GLint level
GLboolean r
[2]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum condition
GLenum GLenum GLsizei count
GLfloat GLfloat f
GLsizei levels
GLint ref
GLfloat n
GLhandleARB obj
[2]
Definition: qopenglext.h:4164
GLboolean reset
Definition: qopenglext.h:2748
const GLubyte * c
Definition: qopenglext.h:12701
GLuint in
Definition: qopenglext.h:8870
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLenum GLenum GLenum input
Definition: qopenglext.h:10816
GLsizei const GLchar *const * string
[0]
Definition: qopenglext.h:694
#define QTEST_MAIN(TestObject)
Definition: qtest.h:664
#define QFAIL(message)
Definition: qtestcase.h:70
#define QVERIFY(statement)
Definition: qtestcase.h:64
#define QTRY_VERIFY(expr)
Definition: qtestcase.h:196
#define QVERIFY2(statement, description)
Definition: qtestcase.h:76
#define Q_OBJECT
Definition: qtmetamacros.h:158
#define slots
Definition: qtmetamacros.h:76
QList< int > results
QFuture< void > future
[5]
future cancel()
QThreadPool pool
run< double >(f)
int operator()()
int member0()
int member1(int in)
int operator()(int in)
static constexpr int defaultState()
void setNewState(int newState)
int operator()(int newState)
static constexpr int defaultState()
void setNewState(QPromise< int > &, int newState)
void operator()(QPromise< int > &promise, int newState)
void operator()(int, int, int, int, int)
void operator()(int, int, int, int, int, int)
int operator()(int a, int b)
double operator()(double a, double b)
void operator()(int)
void operator()(int, int, int)
void operator()(int, int, int, int)
void operator()(QPromise< int > &, double)
static std::atomic< int > count
LifetimeChecker(const LifetimeChecker &)
void operator()(QPromise< double > &)
void operator()(QPromise< double > &, int)
void operator()(QPromise< int > &, int)
void operator()(QPromise< int > &)
void operator()(int)
void operator()(int) const
void fooInt(int) const
int(* fun)()
void stringRefFunction(QString &)
int returnInt1(int i)
void doubleFunction(double)
void recursiveRun(int level)
void reportString2(QPromise< QString > &promise, QString s)
int fn1(int)
void vfn0()
void stringIntFunction(QString)
void reportString1(QPromise< QString > &promise, const QString &s)
int returnInt0()
QAtomicInt count
void lightOverloaded()
void reportN(QPromise< double > &promise, int n)
void light()
int throwFunctionReturn()
void vfn2(double, int *)
void report3(QPromise< int > &promise)
int recursiveResult(int level)
void reportInt0(QPromise< int > &promise)
void reportIntPlusOne(QPromise< int > &promise, int i)
void heavy()
int fn0()
void vfn1(double)
void stringFunction(QString)
int explicitPromise(QPromise< int > &promise, int &i)
void fn()
int fn2(double, int *)
void stringConstRefFunction(const QString &)
void throwFunction()
QMutex mutex