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.h>
30#include <QString>
31#include <QtTest/QtTest>
32
33#include <atomic>
34
35using namespace QtConcurrent;
36
37class tst_QtConcurrentRun: public QObject
38{
39 Q_OBJECT
40private slots:
41 void runLightFunction();
42 void runHeavyFunction();
43 void returnValue();
44 void functionObject();
45 void memberFunctions();
46 void implicitConvertibleTypes();
47 void runWaitLoop();
48 void pollForIsFinished();
49 void recursive();
50#ifndef QT_NO_EXCEPTIONS
51 void exceptions();
52#endif
53 void functor();
54 void lambda();
55 void nullThreadPool();
56 void nullThreadPoolNoLeak();
57};
58
59void light()
60{
61 qDebug(msg: "in function");
62 qDebug(msg: "done function");
63}
64
65void heavy()
66{
67 qDebug(msg: "in function");
68 QString str;
69 for (int i = 0; i < 1000000; ++i)
70 str.append(s: "a");
71 qDebug(msg: "done function");
72}
73
74
75void tst_QtConcurrentRun::runLightFunction()
76{
77 qDebug(msg: "starting function");
78 QFuture<void> future = run(functionPointer: light);
79 qDebug(msg: "waiting");
80 future.waitForFinished();
81 qDebug(msg: "done");
82}
83
84void tst_QtConcurrentRun::runHeavyFunction()
85{
86 QThreadPool pool;
87 qDebug(msg: "starting function");
88 QFuture<void> future = run(pool: &pool, functionPointer: heavy);
89 qDebug(msg: "waiting");
90 future.waitForFinished();
91 qDebug(msg: "done");
92}
93
94int returnInt0()
95{
96 return 10;
97}
98
99int returnInt1(int i)
100{
101 return i;
102}
103
104class A
105{
106public:
107 int member0() { return 10; }
108 int member1(int in) { return in; }
109
110 typedef int result_type;
111 int operator()() { return 10; }
112 int operator()(int in) { return in; }
113};
114
115class AConst
116{
117public:
118 int member0() const { return 10; }
119 int member1(int in) const { return in; }
120
121 typedef int result_type;
122 int operator()() const { return 10; }
123 int operator()(int in) const { return in; }
124};
125
126class ANoExcept
127{
128public:
129 int member0() noexcept { return 10; }
130 int member1(int in) noexcept { return in; }
131
132 typedef int result_type;
133 int operator()() noexcept { return 10; }
134 int operator()(int in) noexcept { return in; }
135};
136
137class AConstNoExcept
138{
139public:
140 int member0() const noexcept { return 10; }
141 int member1(int in) const noexcept { return in; }
142
143 typedef int result_type;
144 int operator()() const noexcept { return 10; }
145 int operator()(int in) const noexcept { return in; }
146};
147
148void tst_QtConcurrentRun::returnValue()
149{
150 QThreadPool pool;
151 QFuture<int> f;
152
153 f = run(functionPointer: returnInt0);
154 QCOMPARE(f.result(), 10);
155 f = run(pool: &pool, functionPointer: returnInt0);
156 QCOMPARE(f.result(), 10);
157
158 A a;
159 f = run(object: &a, fn: &A::member0);
160 QCOMPARE(f.result(), 10);
161 f = run(pool: &pool, object: &a, fn: &A::member0);
162 QCOMPARE(f.result(), 10);
163
164 f = run(object: &a, fn: &A::member1, arg1: 20);
165 QCOMPARE(f.result(), 20);
166 f = run(pool: &pool, object: &a, fn: &A::member1, arg1: 20);
167 QCOMPARE(f.result(), 20);
168
169 f = run(object: a, fn: &A::member0);
170 QCOMPARE(f.result(), 10);
171 f = run(pool: &pool, object: a, fn: &A::member0);
172 QCOMPARE(f.result(), 10);
173
174 f = run(object: a, fn: &A::member1, arg1: 20);
175 QCOMPARE(f.result(), 20);
176 f = run(pool: &pool, object: a, fn: &A::member1, arg1: 20);
177 QCOMPARE(f.result(), 20);
178
179 f = run(functionObject: a);
180 QCOMPARE(f.result(), 10);
181 f = run(pool: &pool, functionObject: a);
182 QCOMPARE(f.result(), 10);
183
184 f = run(functionObject: &a);
185 QCOMPARE(f.result(), 10);
186 f = run(pool: &pool, functionObject: &a);
187 QCOMPARE(f.result(), 10);
188
189 f = run(functionObject: a, arg1: 20);
190 QCOMPARE(f.result(), 20);
191 f = run(pool: &pool, functionObject: a, arg1: 20);
192 QCOMPARE(f.result(), 20);
193
194 f = run(functionObject: &a, arg1: 20);
195 QCOMPARE(f.result(), 20);
196 f = run(pool: &pool, functionObject: &a, arg1: 20);
197 QCOMPARE(f.result(), 20);
198
199 const AConst aConst = AConst();
200 f = run(object: &aConst, fn: &AConst::member0);
201 QCOMPARE(f.result(), 10);
202 f = run(pool: &pool, object: &aConst, fn: &AConst::member0);
203 QCOMPARE(f.result(), 10);
204
205 f = run(object: &aConst, fn: &AConst::member1, arg1: 20);
206 QCOMPARE(f.result(), 20);
207 f = run(pool: &pool, object: &aConst, fn: &AConst::member1, arg1: 20);
208 QCOMPARE(f.result(), 20);
209
210 f = run(object: aConst, fn: &AConst::member0);
211 QCOMPARE(f.result(), 10);
212 f = run(pool: &pool, object: aConst, fn: &AConst::member0);
213 QCOMPARE(f.result(), 10);
214
215 f = run(object: aConst, fn: &AConst::member1, arg1: 20);
216 QCOMPARE(f.result(), 20);
217 f = run(pool: &pool, object: aConst, fn: &AConst::member1, arg1: 20);
218 QCOMPARE(f.result(), 20);
219
220 f = run(functionObject: aConst);
221 QCOMPARE(f.result(), 10);
222 f = run(pool: &pool, functionObject: aConst);
223 QCOMPARE(f.result(), 10);
224
225 f = run(functionObject: &aConst);
226 QCOMPARE(f.result(), 10);
227 f = run(pool: &pool, functionObject: &aConst);
228 QCOMPARE(f.result(), 10);
229
230 f = run(functionObject: aConst, arg1: 20);
231 QCOMPARE(f.result(), 20);
232 f = run(pool: &pool, functionObject: aConst, arg1: 20);
233 QCOMPARE(f.result(), 20);
234
235 f = run(functionObject: &aConst, arg1: 20);
236 QCOMPARE(f.result(), 20);
237 f = run(pool: &pool, functionObject: &aConst, arg1: 20);
238 QCOMPARE(f.result(), 20);
239
240 ANoExcept aNoExcept;
241 f = run(object: &aNoExcept, fn: &ANoExcept::member0);
242 QCOMPARE(f.result(), 10);
243 f = run(pool: &pool, object: &aNoExcept, fn: &ANoExcept::member0);
244 QCOMPARE(f.result(), 10);
245
246 f = run(object: &aNoExcept, fn: &ANoExcept::member1, arg1: 20);
247 QCOMPARE(f.result(), 20);
248 f = run(pool: &pool, object: &aNoExcept, fn: &ANoExcept::member1, arg1: 20);
249 QCOMPARE(f.result(), 20);
250
251 f = run(object: aNoExcept, fn: &ANoExcept::member0);
252 QCOMPARE(f.result(), 10);
253 f = run(pool: &pool, object: aNoExcept, fn: &ANoExcept::member0);
254 QCOMPARE(f.result(), 10);
255
256 f = run(object: aNoExcept, fn: &ANoExcept::member1, arg1: 20);
257 QCOMPARE(f.result(), 20);
258 f = run(pool: &pool, object: aNoExcept, fn: &ANoExcept::member1, arg1: 20);
259 QCOMPARE(f.result(), 20);
260
261 f = run(functionObject: aNoExcept);
262 QCOMPARE(f.result(), 10);
263 f = run(pool: &pool, functionObject: aNoExcept);
264 QCOMPARE(f.result(), 10);
265
266 f = run(functionObject: &aNoExcept);
267 QCOMPARE(f.result(), 10);
268 f = run(pool: &pool, functionObject: &aNoExcept);
269 QCOMPARE(f.result(), 10);
270
271 f = run(functionObject: aNoExcept, arg1: 20);
272 QCOMPARE(f.result(), 20);
273 f = run(pool: &pool, functionObject: aNoExcept, arg1: 20);
274 QCOMPARE(f.result(), 20);
275
276 f = run(functionObject: &aNoExcept, arg1: 20);
277 QCOMPARE(f.result(), 20);
278 f = run(pool: &pool, functionObject: &aNoExcept, arg1: 20);
279 QCOMPARE(f.result(), 20);
280
281 const AConstNoExcept aConstNoExcept = AConstNoExcept();
282 f = run(object: &aConstNoExcept, fn: &AConstNoExcept::member0);
283 QCOMPARE(f.result(), 10);
284 f = run(pool: &pool, object: &aConstNoExcept, fn: &AConstNoExcept::member0);
285 QCOMPARE(f.result(), 10);
286
287 f = run(object: &aConstNoExcept, fn: &AConstNoExcept::member1, arg1: 20);
288 QCOMPARE(f.result(), 20);
289 f = run(pool: &pool, object: &aConstNoExcept, fn: &AConstNoExcept::member1, arg1: 20);
290 QCOMPARE(f.result(), 20);
291
292 f = run(object: aConstNoExcept, fn: &AConstNoExcept::member0);
293 QCOMPARE(f.result(), 10);
294 f = run(pool: &pool, object: aConstNoExcept, fn: &AConstNoExcept::member0);
295 QCOMPARE(f.result(), 10);
296
297 f = run(object: aConstNoExcept, fn: &AConstNoExcept::member1, arg1: 20);
298 QCOMPARE(f.result(), 20);
299 f = run(pool: &pool, object: aConstNoExcept, fn: &AConstNoExcept::member1, arg1: 20);
300 QCOMPARE(f.result(), 20);
301
302 f = run(functionObject: aConstNoExcept);
303 QCOMPARE(f.result(), 10);
304 f = run(pool: &pool, functionObject: aConstNoExcept);
305 QCOMPARE(f.result(), 10);
306
307 f = run(functionObject: &aConstNoExcept);
308 QCOMPARE(f.result(), 10);
309 f = run(pool: &pool, functionObject: &aConstNoExcept);
310 QCOMPARE(f.result(), 10);
311
312 f = run(functionObject: aConstNoExcept, arg1: 20);
313 QCOMPARE(f.result(), 20);
314 f = run(pool: &pool, functionObject: aConstNoExcept, arg1: 20);
315 QCOMPARE(f.result(), 20);
316
317 f = run(functionObject: &aConstNoExcept, arg1: 20);
318 QCOMPARE(f.result(), 20);
319 f = run(pool: &pool, functionObject: &aConstNoExcept, arg1: 20);
320 QCOMPARE(f.result(), 20);
321}
322
323struct TestClass
324{
325 void foo() { }
326 typedef void result_type;
327 void operator()() { }
328 void operator()(int) { }
329 void fooInt(int){ };
330};
331
332struct TestConstClass
333{
334 void foo() const { }
335 typedef void result_type;
336 void operator()() const { }
337 void operator()(int) const { }
338 void fooInt(int) const { };
339};
340
341void tst_QtConcurrentRun::functionObject()
342{
343 QThreadPool pool;
344 QFuture<void> f;
345 TestClass c;
346
347 f = run(functionObject: c);
348 f = run(functionObject: &c);
349 f = run(functionObject: c, arg1: 10);
350 f = run(functionObject: &c, arg1: 10);
351
352 f = run(pool: &pool, functionObject: c);
353 f = run(pool: &pool, functionObject: &c);
354 f = run(pool: &pool, functionObject: c, arg1: 10);
355 f = run(pool: &pool, functionObject: &c, arg1: 10);
356
357 const TestConstClass cc = TestConstClass();
358 f = run(functionObject: cc);
359 f = run(functionObject: &cc);
360 f = run(functionObject: cc, arg1: 10);
361 f = run(functionObject: &cc, arg1: 10);
362
363 f = run(pool: &pool, functionObject: cc);
364 f = run(pool: &pool, functionObject: &cc);
365 f = run(pool: &pool, functionObject: cc, arg1: 10);
366 f = run(pool: &pool, functionObject: &cc, arg1: 10);
367}
368
369
370void tst_QtConcurrentRun::memberFunctions()
371{
372 QThreadPool pool;
373
374 TestClass c;
375
376 run(object: c, fn: &TestClass::foo).waitForFinished();
377 run(object: &c, fn: &TestClass::foo).waitForFinished();
378 run(object: c, fn: &TestClass::fooInt, arg1: 10).waitForFinished();
379 run(object: &c, fn: &TestClass::fooInt, arg1: 10).waitForFinished();
380
381 run(pool: &pool, object: c, fn: &TestClass::foo).waitForFinished();
382 run(pool: &pool, object: &c, fn: &TestClass::foo).waitForFinished();
383 run(pool: &pool, object: c, fn: &TestClass::fooInt, arg1: 10).waitForFinished();
384 run(pool: &pool, object: &c, fn: &TestClass::fooInt, arg1: 10).waitForFinished();
385
386 const TestConstClass cc = TestConstClass();
387 run(object: cc, fn: &TestConstClass::foo).waitForFinished();
388 run(object: &cc, fn: &TestConstClass::foo).waitForFinished();
389 run(object: cc, fn: &TestConstClass::fooInt, arg1: 10).waitForFinished();
390 run(object: &cc, fn: &TestConstClass::fooInt, arg1: 10).waitForFinished();
391
392 run(pool: &pool, object: cc, fn: &TestConstClass::foo).waitForFinished();
393 run(pool: &pool, object: &cc, fn: &TestConstClass::foo).waitForFinished();
394 run(pool: &pool, object: cc, fn: &TestConstClass::fooInt, arg1: 10).waitForFinished();
395 run(pool: &pool, object: &cc, fn: &TestConstClass::fooInt, arg1: 10).waitForFinished();
396}
397
398
399void doubleFunction(double)
400{
401
402}
403
404void stringConstRefFunction(const QString &)
405{
406
407}
408
409void stringRefFunction(QString &)
410{
411
412}
413
414void stringFunction(QString)
415{
416
417}
418
419void stringIntFunction(QString)
420{
421
422}
423
424
425void tst_QtConcurrentRun::implicitConvertibleTypes()
426{
427 QThreadPool pool;
428
429 double d;
430 run(functionPointer: doubleFunction, arg1: d).waitForFinished();
431 run(pool: &pool, functionPointer: doubleFunction, arg1: d).waitForFinished();
432 int i;
433 run(functionPointer: doubleFunction, arg1: d).waitForFinished();
434 run(pool: &pool, functionPointer: doubleFunction, arg1: d).waitForFinished();
435 run(functionPointer: doubleFunction, arg1: i).waitForFinished();
436 run(pool: &pool, functionPointer: doubleFunction, arg1: i).waitForFinished();
437 run(functionPointer: doubleFunction, arg1: 10).waitForFinished();
438 run(pool: &pool, functionPointer: doubleFunction, arg1: 10).waitForFinished();
439 run(functionPointer: stringFunction, arg1: QLatin1String("Foo")).waitForFinished();
440 run(pool: &pool, functionPointer: stringFunction, arg1: QLatin1String("Foo")).waitForFinished();
441 run(functionPointer: stringConstRefFunction, arg1: QLatin1String("Foo")).waitForFinished();
442 run(pool: &pool, functionPointer: stringConstRefFunction, arg1: QLatin1String("Foo")).waitForFinished();
443 QString string;
444 run(functionPointer: stringRefFunction, arg1: string).waitForFinished();
445 run(pool: &pool, functionPointer: stringRefFunction, arg1: string).waitForFinished();
446}
447
448void fn() { }
449
450void tst_QtConcurrentRun::runWaitLoop()
451{
452 for (int i = 0; i < 1000; ++i)
453 run(functionPointer: fn).waitForFinished();
454}
455
456static bool allFinished(const QList<QFuture<void> > &futures)
457{
458 auto hasNotFinished = [](const QFuture<void> &future) { return !future.isFinished(); };
459 return std::find_if(first: futures.cbegin(), last: futures.cend(), pred: hasNotFinished)
460 == futures.constEnd();
461}
462
463static void runFunction()
464{
465 QEventLoop loop;
466 QTimer::singleShot(interval: 20, receiver: &loop, slot: &QEventLoop::quit);
467 loop.exec();
468}
469
470void tst_QtConcurrentRun::pollForIsFinished()
471{
472 const int numThreads = std::max(a: 4, b: 2 * QThread::idealThreadCount());
473 QThreadPool::globalInstance()->setMaxThreadCount(numThreads);
474
475 QFutureSynchronizer<void> synchronizer;
476 for (int i = 0; i < numThreads; ++i)
477 synchronizer.addFuture(future: QtConcurrent::run(functionPointer: &runFunction));
478
479 // same as synchronizer.waitForFinished() but with a timeout
480 QTRY_VERIFY(allFinished(synchronizer.futures()));
481}
482
483
484QAtomicInt count;
485
486void recursiveRun(int level)
487{
488 count.ref();
489 if (--level > 0) {
490 QFuture<void> f1 = run(functionPointer: recursiveRun, arg1: level);
491 QFuture<void> f2 = run(functionPointer: recursiveRun, arg1: level);
492 f1.waitForFinished();
493 f2.waitForFinished();
494 }
495}
496
497int recursiveResult(int level)
498{
499 count.ref();
500 if (--level > 0) {
501 QFuture<int> f1 = run(functionPointer: recursiveResult, arg1: level);
502 QFuture<int> f2 = run(functionPointer: recursiveResult, arg1: level);
503 return f1.result() + f2.result();
504 }
505 return 1;
506}
507
508void tst_QtConcurrentRun::recursive()
509{
510 int levels = 15;
511
512 for (int i = 0; i < QThread::idealThreadCount(); ++i) {
513 count.storeRelaxed(newValue: 0);
514 QThreadPool::globalInstance()->setMaxThreadCount(i);
515 recursiveRun(level: levels);
516 QCOMPARE(count.loadRelaxed(), (int)std::pow(2.0, levels) - 1);
517 }
518
519 for (int i = 0; i < QThread::idealThreadCount(); ++i) {
520 count.storeRelaxed(newValue: 0);
521 QThreadPool::globalInstance()->setMaxThreadCount(i);
522 recursiveResult(level: levels);
523 QCOMPARE(count.loadRelaxed(), (int)std::pow(2.0, levels) - 1);
524 }
525}
526
527int e;
528void vfn0()
529{
530 ++e;
531}
532
533int fn0()
534{
535 return 1;
536}
537
538void vfn1(double)
539{
540 ++e;
541}
542
543int fn1(int)
544{
545 return 1;
546}
547
548void vfn2(double, int *)
549{
550 ++e;
551}
552
553int fn2(double, int *)
554{
555 return 1;
556}
557
558
559#ifndef QT_NO_EXCEPTIONS
560void throwFunction()
561{
562 throw QException();
563}
564
565int throwFunctionReturn()
566{
567 throw QException();
568 return 0;
569}
570
571class SlowTask : public QRunnable
572{
573public:
574 static QAtomicInt cancel;
575 void run() override {
576 int iter = 60;
577 while (--iter && !cancel.loadRelaxed())
578 QThread::currentThread()->msleep(25);
579 }
580};
581
582QAtomicInt SlowTask::cancel;
583
584void tst_QtConcurrentRun::exceptions()
585{
586 QThreadPool pool;
587 bool caught;
588
589 caught = false;
590 try {
591 QtConcurrent::run(functionPointer: throwFunction).waitForFinished();
592 } catch (QException &) {
593 caught = true;
594 }
595 if (!caught)
596 QFAIL("did not get exception");
597
598 caught = false;
599 try {
600 QtConcurrent::run(pool: &pool, functionPointer: throwFunction).waitForFinished();
601 } catch (QException &) {
602 caught = true;
603 }
604 if (!caught)
605 QFAIL("did not get exception");
606
607 caught = false;
608 try {
609 QtConcurrent::run(functionPointer: throwFunctionReturn).waitForFinished();
610 } catch (QException &) {
611 caught = true;
612 }
613 if (!caught)
614 QFAIL("did not get exception");
615
616 caught = false;
617 try {
618 QtConcurrent::run(pool: &pool, functionPointer: throwFunctionReturn).waitForFinished();
619 } catch (QException &) {
620 caught = true;
621 }
622 if (!caught)
623 QFAIL("did not get exception");
624
625 caught = false;
626 try {
627 QtConcurrent::run(pool: &pool, functionPointer: throwFunctionReturn).result();
628 } catch (QException &) {
629 caught = true;
630 }
631 QVERIFY2(caught, "did not get exception");
632
633 // Force the task to be run on this thread.
634 caught = false;
635 QThreadPool shortPool;
636 shortPool.setMaxThreadCount(1);
637 SlowTask *st = new SlowTask();
638 try {
639 shortPool.start(runnable: st);
640 QtConcurrent::run(pool: &shortPool, functionPointer: throwFunctionReturn).result();
641 } catch (QException &) {
642 caught = true;
643 }
644
645 SlowTask::cancel.storeRelaxed(newValue: true);
646
647 QVERIFY2(caught, "did not get exception");
648}
649#endif
650
651// Compiler supports decltype
652struct Functor {
653 int operator()() { return 42; }
654 double operator()(double a, double b) { return a/b; }
655 int operator()(int a, int b) { return a/b; }
656 void operator()(int) { }
657 void operator()(int, int, int) { }
658 void operator()(int, int, int, int) { }
659 void operator()(int, int, int, int, int) { }
660 void operator()(int, int, int, int, int, int) { }
661};
662
663// This tests functor without result_type; decltype need to be supported by the compiler.
664void tst_QtConcurrentRun::functor()
665{
666 Functor f;
667 {
668 QFuture<int> fut = QtConcurrent::run(functor: f);
669 QCOMPARE(fut.result(), 42);
670 }
671 {
672 QFuture<double> fut = QtConcurrent::run(functor: f, arg1: 8.5, arg2: 1.8);
673 QCOMPARE(fut.result(), (8.5/1.8));
674 }
675 {
676 QFuture<int> fut = QtConcurrent::run(functor: f, arg1: 19, arg2: 3);
677 QCOMPARE(fut.result(), int(19/3));
678 }
679 {
680 QtConcurrent::run(functor: f, arg1: 1).waitForFinished();
681 QtConcurrent::run(functor: f, arg1: 1,arg2: 2).waitForFinished();
682 QtConcurrent::run(functor: f, arg1: 1,arg2: 2,arg3: 3).waitForFinished();
683 QtConcurrent::run(functor: f, arg1: 1,arg2: 2,arg3: 3,arg4: 4).waitForFinished();
684 QtConcurrent::run(functor: f, arg1: 1,arg2: 2,arg3: 3,arg4: 4,arg5: 5).waitForFinished();
685 }
686 // and now with explicit pool:
687 QThreadPool pool;
688 {
689 QFuture<int> fut = QtConcurrent::run(pool: &pool, functor: f);
690 QCOMPARE(fut.result(), 42);
691 }
692 {
693 QFuture<double> fut = QtConcurrent::run(pool: &pool, functor: f, arg1: 8.5, arg2: 1.8);
694 QCOMPARE(fut.result(), (8.5/1.8));
695 }
696 {
697 QFuture<int> fut = QtConcurrent::run(pool: &pool, functor: f, arg1: 19, arg2: 3);
698 QCOMPARE(fut.result(), int(19/3));
699 }
700 {
701 QtConcurrent::run(pool: &pool, functor: f, arg1: 1).waitForFinished();
702 QtConcurrent::run(pool: &pool, functor: f, arg1: 1,arg2: 2).waitForFinished();
703 QtConcurrent::run(pool: &pool, functor: f, arg1: 1,arg2: 2,arg3: 3).waitForFinished();
704 QtConcurrent::run(pool: &pool, functor: f, arg1: 1,arg2: 2,arg3: 3,arg4: 4).waitForFinished();
705 QtConcurrent::run(pool: &pool, functor: f, arg1: 1,arg2: 2,arg3: 3,arg4: 4,arg5: 5).waitForFinished();
706 }
707}
708
709// Compiler supports lambda
710void tst_QtConcurrentRun::lambda()
711{
712 QCOMPARE(QtConcurrent::run([](){ return 45; }).result(), 45);
713 QCOMPARE(QtConcurrent::run([](int a){ return a+15; }, 12).result(), 12+15);
714 QCOMPARE(QtConcurrent::run([](int a, double b){ return a + b; }, 12, 15).result(), double(12+15));
715 QCOMPARE(QtConcurrent::run([](int a , int, int, int, int b){ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5);
716
717 {
718 QString str { "Hello World Foo" };
719 QFuture<QStringList> f1 = QtConcurrent::run(functor: [&](){ return str.split(sep: ' '); });
720 auto r = f1.result();
721 QCOMPARE(r, QStringList({"Hello", "World", "Foo"}));
722 }
723
724 // and now with explicit pool:
725 QThreadPool pool;
726 QCOMPARE(QtConcurrent::run(&pool, [](){ return 45; }).result(), 45);
727 QCOMPARE(QtConcurrent::run(&pool, [](int a){ return a+15; }, 12).result(), 12+15);
728 QCOMPARE(QtConcurrent::run(&pool, [](int a, double b){ return a + b; }, 12, 15).result(), double(12+15));
729 QCOMPARE(QtConcurrent::run(&pool, [](int a , int, int, int, int b){ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5);
730
731 {
732 QString str { "Hello World Foo" };
733 QFuture<QStringList> f1 = QtConcurrent::run(pool: &pool, functor: [&](){ return str.split(sep: ' '); });
734 auto r = f1.result();
735 QCOMPARE(r, QStringList({"Hello", "World", "Foo"}));
736 }
737}
738
739// QTBUG-98901
740void tst_QtConcurrentRun::nullThreadPool()
741{
742 QThreadPool *pool = nullptr;
743 std::atomic<bool> isInvoked(false);
744 auto future = run(pool, functor: [&] { isInvoked = true; });
745 future.waitForFinished();
746 QVERIFY(future.isCanceled());
747 QVERIFY(!isInvoked);
748}
749
750struct LifetimeChecker
751{
752 LifetimeChecker() { ++count; }
753 LifetimeChecker(const LifetimeChecker &) { ++count; }
754 ~LifetimeChecker() { --count; }
755
756 void operator()() { }
757
758 static std::atomic<int> count;
759};
760std::atomic<int> LifetimeChecker::count{ 0 };
761
762void tst_QtConcurrentRun::nullThreadPoolNoLeak()
763{
764 {
765 QThreadPool *pool = nullptr;
766 auto future = run(pool, functor: LifetimeChecker());
767 future.waitForFinished();
768 }
769 QCOMPARE(LifetimeChecker::count, 0);
770}
771
772QTEST_MAIN(tst_QtConcurrentRun)
773#include "tst_qtconcurrentrun.moc"
774

source code of qtbase/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp