boost::capy::when_any
Wait for the first awaitable to complete.
Synopsis
Declared in <boost/capy/when_any.hpp>
template<
IoAwaitable A0,
IoAwaitable... As>
[[nodiscard]]
task</* implementation-defined */>
when_any(
A0 a0,
As... as);
Description
Races multiple heterogeneous awaitables concurrently and returns when the first one completes. The result includes the winner's index and a deduplicated variant containing the result value.
Suspends
The calling coroutine suspends when co_await is invoked. All awaitables are launched concurrently and execute in parallel. The coroutine resumes only after all awaitables have completed, even though the winner is determined by the first to finish.
Completion Conditions
-
Winner is determined when the first awaitable completes (success or exception)
-
Only one task can claim winner status via atomic compare‐exchange
-
Once a winner exists, stop is requested for all remaining siblings
-
Parent coroutine resumes only after all siblings acknowledge completion
-
The winner's result is returned; if the winner threw, the exception is rethrown
Cancellation Semantics
Cancellation is supported via stop_token propagated through the IoAwaitable protocol:
-
Each child awaitable receives a stop_token derived from a shared stop_source
-
When the parent's stop token is activated, the stop is forwarded to all children
-
When a winner is determined, stop_source_.request_stop() is called immediately
-
Siblings must handle cancellation gracefully and complete before parent resumes
-
Stop requests are cooperative; tasks must check and respond to them
Concurrency/Overlap
All awaitables are launched concurrently before any can complete. The launcher iterates through the arguments, starting each task on the caller's executor. Tasks may execute in parallel on multi‐threaded executors or interleave on single‐threaded executors. There is no guaranteed ordering of task completion.
Notable Error Conditions
-
Winner exception: if the winning task threw, that exception is rethrown
-
Non‐winner exceptions: silently discarded (only winner's result matters)
-
Cancellation: tasks may complete via cancellation without throwing
Example
task<void> example() {
auto [index, result] = co_await when_any(
fetch_from_primary(), // task<Response>
fetch_from_backup() // task<Response>
);
// index is 0 or 1, result holds the winner's Response
auto response = std::get<Response>(result);
}
Example with Heterogeneous Types
task<void> mixed_types() {
auto [index, result] = co_await when_any(
fetch_int(), // task<int>
fetch_string() // task<std::string>
);
if (index == 0)
std::cout << "Got int: " << std::get<int>(result) << "\n";
else
std::cout << "Got string: " << std::get<std::string>(result) << "\n";
}
Remarks
Awaitables are moved into the coroutine frame; original objects become empty after the call. When multiple awaitables share the same return type, the variant is deduplicated to contain only unique types. Use the winner index to determine which awaitable completed first. Void awaitables contribute std::monostate to the variant.
Exceptions
Name |
Thrown on |
|
the winner's exception if the winning task threw an exception. |
Template Parameters
| Name | Description |
|---|---|
A0 |
First awaitable type (must satisfy IoAwaitable). |
As |
Remaining awaitable types (must satisfy IoAwaitable). |
Parameters
| Name | Description |
|---|---|
a0 |
The first awaitable to race. |
as |
Additional awaitables to race concurrently. |
See Also
when_all, IoAwaitable
Created with MrDocs