diff options
-rw-r--r-- | async/autotests/asynctest.cpp | 52 | ||||
-rw-r--r-- | async/src/async.h | 19 |
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 | ||
70 | private: | 73 | private: |
@@ -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 | */ | ||
568 | void 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 | */ | ||
594 | void 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 | ||
563 | void AsyncTest::benchmarkSyncThenExecutor() | 615 | void 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 | */ |
44 | namespace Async { | 61 | namespace Async { |
45 | 62 | ||