Skip to content

Latest commit

 

History

History
122 lines (93 loc) · 4.1 KB

race.adoc

File metadata and controls

122 lines (93 loc) · 4.1 KB

cobalt/race.hpp

The race function can be used to co_await one awaitable out of a set of them.

It can be called as a variadic function with multiple awaitable or as on a range of awaitables.

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 awaitables

  2. wait for a vector of awaitables

The first parameter so race can be a uniform random bit generator.

Signatures of race
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 Wait

When arguments are passed as rvalue reference, the race will attempt to use .interrupt_await on the 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:

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, generator and 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

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.

Outline

// Concept for the random number generator.
link:../../include/boost/cobalt/race.hpp[role=include]

// 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.