From ef9e47279a9d066ccb93ff1946d20d3b13953957 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Tue, 31 Mar 2015 12:09:21 +0200 Subject: Attempt of a description how async is supposed to work, failing async lifetime tests. --- async/autotests/asynctest.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++ async/src/async.h | 19 +++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) 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: void testChainingRunningJob(); void testChainingFinishedJob(); + void testLifetimeWithoutHandle(); + void testLifetimeWithHandle(); + void benchmarkSyncThenExecutor(); private: @@ -558,7 +561,56 @@ void AsyncTest::testChainingFinishedJob() QCOMPARE(future2.value(), 84); } +/* + * We want to be able to execute jobs without keeping a handle explicitly alive. + * If the future handle inside the continuation would keep the executor alive, that would probably already work. + */ +void AsyncTest::testLifetimeWithoutHandle() +{ + bool done = false; + { + auto job = Async::start([&done](Async::Future &future) { + QTimer *timer = new QTimer(); + QObject::connect(timer, &QTimer::timeout, + [&future, &done]() { + done = true; + future.setFinished(); + }); + QObject::connect(timer, &QTimer::timeout, + timer, &QObject::deleteLater); + timer->setSingleShot(true); + timer->start(500); + }); + job.exec(); + } + QTRY_VERIFY(done); +} + +/* + * The future handle should keep the executor alive, and the future reference should probably not become invalid inside the continuation, + * until the job is done (alternatively a copy of the future inside the continuation should work as well). + */ +void AsyncTest::testLifetimeWithHandle() +{ + Async::Future future; + { + auto job = Async::start([](Async::Future &future) { + QTimer *timer = new QTimer(); + QObject::connect(timer, &QTimer::timeout, + [&future]() { + future.setFinished(); + }); + QObject::connect(timer, &QTimer::timeout, + timer, &QObject::deleteLater); + timer->setSingleShot(true); + timer->start(500); + }); + future = job.exec(); + } + + QTRY_VERIFY(future.isFinished()); +} void AsyncTest::benchmarkSyncThenExecutor() { 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 @@ /* - * TODO: instead of passing the future objects callbacks could be provided for result reporting (we can still use the future object internally + * API to help write async code. + * + * This API is based around jobs that take lambdas to execute asynchronous tasks. Each async operation can take a continuation, + * that can then be used to execute further async operations. That way it is possible to build async chains of operations, + * that can be stored and executed later on. Jobs can be composed, similarly to functions. + * + * Relations between the components: + * * Job: description of what should happen + * * Executor: Running execution of a job, the process that calculates the result. + * * Future: Representation of the result that is being calculated + * + * Lifetime: + * * Before a job is executed is treated like a normal value on the stack. + * * As soon as the job is executed, a heap allocated executor keeps the task running until complete. The associated future handle remains + * valid until the task is complete. To abort a job it has to be killed through the future handle. + * TODO: Can we tie the lifetime of the executor to the last available future handle? + * + * TODO: Progress reporting through future */ namespace Async { -- cgit v1.2.3