diff --git a/doc/modules/ROOT/pages/4.coroutines/4d.io-awaitable.adoc b/doc/modules/ROOT/pages/4.coroutines/4d.io-awaitable.adoc index 80b6f2df9..48672d51d 100644 --- a/doc/modules/ROOT/pages/4.coroutines/4d.io-awaitable.adoc +++ b/doc/modules/ROOT/pages/4.coroutines/4d.io-awaitable.adoc @@ -215,6 +215,8 @@ stop_cb_.emplace(env->stop_token, h); // h is a raw coroutine_handle See xref:4.coroutines/4e.cancellation.adoc#stoppable-awaitables[Implementing Stoppable Awaitables] for a complete example. +For a production implementation of this exact pattern, read the source of `delay_awaitable` (xref:reference:boost/capy/delay_awaitable.adoc[`delay_awaitable`]): it schedules a timer, registers a stop callback that posts the resume through the executor, and arbitrates between the timer and cancellation with a single atomic claim. + == Reference [cols="1,3"] diff --git a/doc/modules/ROOT/pages/4.coroutines/4f.composition.adoc b/doc/modules/ROOT/pages/4.coroutines/4f.composition.adoc index d4750b19b..eddf23886 100644 --- a/doc/modules/ROOT/pages/4.coroutines/4f.composition.adoc +++ b/doc/modules/ROOT/pages/4.coroutines/4f.composition.adoc @@ -228,9 +228,31 @@ task process_all(std::vector const& items) } ---- +=== Asynchronous Sleep + +`delay` is the awaitable counterpart to `std::this_thread::sleep_for`. Instead of blocking the thread, it suspends the current coroutine until the duration elapses, leaving the thread free to run other coroutines in the meantime: + +[source,cpp] +---- +#include + +task<> example() +{ + auto [ec] = co_await delay(100ms); + // 100ms have elapsed; other coroutines ran on this thread while we waited +} +---- + +[NOTE] +==== +A thread is *not* consumed per sleeping coroutine. All concurrently sleeping coroutines on the same execution context share a single timer thread, so a thousand simultaneous `delay()` calls cost one thread, not a thousand. +==== + +`delay` is cancellable. If the environment's stop token is activated before the deadline, the coroutine resumes early with `ec` set to `error::canceled` (compare with `cond::canceled`); otherwise `ec` is clear. A zero or negative duration completes synchronously without scheduling a timer. + === Timeout -The `timeout` combinator races an awaitable against a deadline: +The `timeout` combinator races an awaitable against a deadline. It is built directly on `delay` — the inner awaitable is run against a `delay` of the given duration, and whichever completes first cancels the other: [source,cpp] ---- @@ -281,6 +303,12 @@ This design ensures proper context propagation to all children. | `` | First-completion racing with when_any +| `` +| Asynchronous sleep that suspends instead of blocking the thread + +| `` +| Race an awaitable against a deadline + | `` | Race an awaitable against a deadline |===