stoppable_awaitable
An awaitable is stoppable if it participates in the stoppable awaitable
protocol by accepting both a dispatcher and a stop token in its
await_suspend method.
Requires: C++20
Synopsis
Defined in header <boost/capy/affine.hpp>
namespace boost::capy {
template<typename A, typename D, typename P = void>
concept stoppable_awaitable =
affine_awaitable<A, D, P> &&
requires(A a, std::coroutine_handle<P> h, D const& d, std::stop_token token) {
a.await_suspend(h, d, token);
};
} // namespace boost::capy
Description
The stoppable awaitable protocol extends affine_awaitable to enable
automatic stop token propagation through coroutine chains. When a task
has a stop token, it passes the token to any stoppable awaitables it awaits.
A stoppable awaitable must provide both overloads of await_suspend:
-
await_suspend(h, d)— for callers without stop tokens -
await_suspend(h, d, token)— for callers with stop tokens
The awaitable should use the stop token to support cancellation of the underlying operation.
Preconditions
-
The dispatcher
dremains valid until the awaitable resumes the caller -
The stop token
tokenremains valid until the operation completes
Valid Expressions
Given:
-
a— a value of typeA -
h— a value of typestd::coroutine_handle<P> -
d— a const value of typeDsatisfyingdispatcher<D, P> -
token— a value of typestd::stop_token
| Expression | Return Type | Description |
|---|---|---|
|
|
Return |
|
(unspecified) |
Suspend without cancellation support |
|
(unspecified) |
Suspend with cancellation support via the stop token |
|
(unspecified) |
Return the operation result or rethrow any exception |
Example
#include <boost/capy/affine.hpp>
#include <stop_token>
using boost::capy::coro;
using boost::capy::stoppable_awaitable;
using boost::capy::any_dispatcher;
struct stoppable_timer
{
std::chrono::milliseconds duration_;
bool cancelled_ = false;
bool await_ready() const noexcept
{
return duration_.count() <= 0;
}
// Affine path (no cancellation)
template<typename Dispatcher>
auto await_suspend(coro h, Dispatcher const& d)
{
start_timer(duration_, [h, &d] { d(h); });
return std::noop_coroutine();
}
// Stoppable path (with cancellation)
template<typename Dispatcher>
auto await_suspend(coro h, Dispatcher const& d, std::stop_token token)
{
if (token.stop_requested())
{
cancelled_ = true;
return d(h); // Resume immediately
}
auto timer_handle = start_timer(duration_, [h, &d] { d(h); });
// Cancel timer if stop requested
std::stop_callback cb(token, [timer_handle] {
cancel_timer(timer_handle);
});
return std::noop_coroutine();
}
void await_resume()
{
if (cancelled_)
throw std::runtime_error("cancelled");
}
};
static_assert(stoppable_awaitable<stoppable_timer, any_dispatcher>);
See Also
-
dispatcher — The dispatcher concept
-
affine_awaitable — Base protocol without cancellation
-
Cancellation — Tutorial on stop token propagation