summaryrefslogtreecommitdiffstats
path: root/async
diff options
context:
space:
mode:
Diffstat (limited to 'async')
-rw-r--r--async/autotests/asynctest.cpp52
-rw-r--r--async/src/async.h19
2 files changed, 70 insertions, 1 deletions
diff --git a/async/autotests/asynctest.cpp b/async/autotests/asynctest.cpp
index 1074ff0..85f5ea5 100644
--- a/async/autotests/asynctest.cpp
+++ b/async/autotests/asynctest.cpp
@@ -65,6 +65,9 @@ private Q_SLOTS:
65 void testChainingRunningJob(); 65 void testChainingRunningJob();
66 void testChainingFinishedJob(); 66 void testChainingFinishedJob();
67 67
68 void testLifetimeWithoutHandle();
69 void testLifetimeWithHandle();
70
68 void benchmarkSyncThenExecutor(); 71 void benchmarkSyncThenExecutor();
69 72
70private: 73private:
@@ -558,7 +561,56 @@ void AsyncTest::testChainingFinishedJob()
558 QCOMPARE(future2.value(), 84); 561 QCOMPARE(future2.value(), 84);
559} 562}
560 563
564/*
565 * We want to be able to execute jobs without keeping a handle explicitly alive.
566 * If the future handle inside the continuation would keep the executor alive, that would probably already work.
567 */
568void AsyncTest::testLifetimeWithoutHandle()
569{
570 bool done = false;
571 {
572 auto job = Async::start<void>([&done](Async::Future<void> &future) {
573 QTimer *timer = new QTimer();
574 QObject::connect(timer, &QTimer::timeout,
575 [&future, &done]() {
576 done = true;
577 future.setFinished();
578 });
579 QObject::connect(timer, &QTimer::timeout,
580 timer, &QObject::deleteLater);
581 timer->setSingleShot(true);
582 timer->start(500);
583 });
584 job.exec();
585 }
561 586
587 QTRY_VERIFY(done);
588}
589
590/*
591 * The future handle should keep the executor alive, and the future reference should probably not become invalid inside the continuation,
592 * until the job is done (alternatively a copy of the future inside the continuation should work as well).
593 */
594void AsyncTest::testLifetimeWithHandle()
595{
596 Async::Future<void> future;
597 {
598 auto job = Async::start<void>([](Async::Future<void> &future) {
599 QTimer *timer = new QTimer();
600 QObject::connect(timer, &QTimer::timeout,
601 [&future]() {
602 future.setFinished();
603 });
604 QObject::connect(timer, &QTimer::timeout,
605 timer, &QObject::deleteLater);
606 timer->setSingleShot(true);
607 timer->start(500);
608 });
609 future = job.exec();
610 }
611
612 QTRY_VERIFY(future.isFinished());
613}
562 614
563void AsyncTest::benchmarkSyncThenExecutor() 615void AsyncTest::benchmarkSyncThenExecutor()
564{ 616{
diff --git a/async/src/async.h b/async/src/async.h
index 8da3daa..dc3889b 100644
--- a/async/src/async.h
+++ b/async/src/async.h
@@ -39,7 +39,24 @@
39 39
40 40
41/* 41/*
42 * TODO: instead of passing the future objects callbacks could be provided for result reporting (we can still use the future object internally 42 * API to help write async code.
43 *
44 * This API is based around jobs that take lambdas to execute asynchronous tasks. Each async operation can take a continuation,
45 * that can then be used to execute further async operations. That way it is possible to build async chains of operations,
46 * that can be stored and executed later on. Jobs can be composed, similarly to functions.
47 *
48 * Relations between the components:
49 * * Job: description of what should happen
50 * * Executor: Running execution of a job, the process that calculates the result.
51 * * Future: Representation of the result that is being calculated
52 *
53 * Lifetime:
54 * * Before a job is executed is treated like a normal value on the stack.
55 * * As soon as the job is executed, a heap allocated executor keeps the task running until complete. The associated future handle remains
56 * valid until the task is complete. To abort a job it has to be killed through the future handle.
57 * TODO: Can we tie the lifetime of the executor to the last available future handle?
58 *
59 * TODO: Progress reporting through future
43 */ 60 */
44namespace Async { 61namespace Async {
45 62