2
0
mirror of https://github.com/boostorg/cobalt.git synced 2026-01-24 05:42:13 +00:00
Files
cobalt/doc/reference/race.adoc
Klemens Morgenstern b807c700dc doc typo fixes
2026-01-11 07:27:47 +08:00

122 lines
4.1 KiB
Plaintext

[#race]
== cobalt/race.hpp
The `race` function can be used to `co_await` one <<awaitable, awaitable>> out of a set of them.
It can be called as a variadic function with multiple <<awaitable, awaitable>> or as on a range of <<awaitable, awaitables>>.
[source,cpp]
----
cobalt::promise<void> task1();
cobalt::promise<void> task2();
cobalt::promise<void> do_wait()
{
co_await cobalt::race(task1(), task2()); // <1>
std::vector<cobalt::promise<void>> aws {task1(), task2()};
co_await cobalt::race(aws); // <2>
}
----
<1> Wait for a variadic set of <<awaitable, awaitables>>
<2> wait for a vector of <<awaitable, awaitables>>
The first parameter so `race` can be a https://en.cppreference.com/w/cpp/named_req/UniformRandomBitGenerator[uniform random bit generator].
.Signatures of race
[source, cpp]
----
extern promise<void> pv1, pv2;
std::vector<promise<void>> pvv;
std::default_random_engine rdm{1};
// if everything returns void race returns the index
std::size_t r1 = co_await race(pv1, pv2);
std::size_t r2 = co_await race(rdm, pv1, pv2);
std::size_t r3 = co_await race(pvv);
std::size_t r4 = co_await race(rdm, pvv);
// variant if not everything is void. void become monostate
extern promise<int> pi1, pi2;
variant2::variant<monostate, int, int> r5 = co_await race(pv1, pi1, pi2);
variant2::variant<monostate, int, int> r6 = co_await race(rdm, pv1, pi1, pi2);
// a range returns a pair of the index and the result if non-void
std::vector<promise<int>> piv;
std::pair<std::size_t, int> r7 = co_await race(piv);
std::pair<std::size_t, int> r8 = co_await race(rdm, piv);
----
[#interrupt_await]
=== Interrupt Wait
When arguments are passed as rvalue reference, the race will attempt to use `.interrupt_await`
on the <<awaitable, awaitable>> to signal the awaitable to complete now and that the result will be ignored.
If supported, the <<awaitable>> must resume the awaiting coroutine before `interrupt_await` returns.
If the `race` doesn't detect the function, it will send a cancellation.
This means that you can reuse race like this:
[source,cpp]
----
cobalt::promise<void> do_wait()
{
auto t1 = task1();
auto t2 = task2();
co_await cobalt::race(t1, t2); // <1>
co_await cobalt::race(t1, t2); // <2>
}
----
<1> Wait for the first task to complete
<2> Wait for the other task to complete
This is supported by <<promise, promise>>, <<generator, generator>> and <<gather, gather>>.
The `race` will invoke the functions of the `awaitable` as if used in a `co_await` expression
or not evaluate them at all.
[#left_race]
=== `left_race`
The `left_race` functions are like `race` but follow a strict left-to-right scan.
This can lead to starvation issues, which is why this is not the recommended default, but can
be useful for prioritization if proper care is taken.
[#race-outline]
=== Outline
[source,cpp,subs=+quotes]
----
// Concept for the random number generator.
include::../../include/boost/cobalt/race.hpp[tag=concept]
// Variadic race with a custom random number generator
template<asio::cancellation_type Ct = asio::cancellation_type::all,
uniform_random_bit_generator URBG, awaitable ... Promise>
__awaitable__ race(URBG && g, Promise && ... p);
// Ranged race with a custom random number generator
template<asio::cancellation_type Ct = asio::cancellation_type::all,
uniform_random_bit_generator URBG, range<awaitable> PromiseRange>
__awaitable__ race(URBG && g, PromiseRange && p);
// Variadic race with the default random number generator
template<asio::cancellation_type Ct = asio::cancellation_type::all, awaitable... Promise>
__awaitable__ race(Promise && ... p);
// Ranged race with the default random number generator
template<asio::cancellation_type Ct = asio::cancellation_type::all, range<awaitable>>
__awaitable__ race(PromiseRange && p);
// Variadic left race
template<asio::cancellation_type Ct = asio::cancellation_type::all, awaitable... Promise>
__awaitable__ left_race(Promise && ... p);
// Ranged left race
template<asio::cancellation_type Ct = asio::cancellation_type::all, range<awaitable>>
__awaitable__ left_race(PromiseRange && p);
----
NOTE: Selecting an empty range will cause an exception to be thrown.