Skip to main content
Pigweed's logo Pigweed
code_xml
  1. Home
  2. Reference
  3. C/C++
  4. Async & concurrency
  5. pw_async2
  6. Combinators
Loading...
Searching...
No Matches

Overview

Helpers for interacting with multiples futures.

Learn more: Combinators

Classes

class  pw::async2::JoinFuture< Futures >
 
class  pw::async2::SelectFuture< Futures >
 

Macros

#define PW_SELECT(lhs, cx, ...)    PW_TRY_READY_ASSIGN(lhs, ::pw::async2::internal::PendSelect(cx, __VA_ARGS__))
 
#define PW_CO_SELECT(lhs, ...)    lhs = co_await ::pw::async2::internal::InPlaceSelectFuture(__VA_ARGS__)
 

Functions

template<typename... Futures>
 pw::async2::JoinFuture (Futures &&...) -> JoinFuture< Futures... >
 
template<typename... Futures>
constexpr auto pw::async2::Join (Futures &&... futures)
 
template<typename... Futures>
 pw::async2::SelectFuture (Futures &&...) -> SelectFuture< Futures... >
 
template<typename... Futures>
SelectFuture< Futures... > pw::async2::Select (Futures &&... futures)
 

Macro Definition Documentation

◆ PW_CO_SELECT

#define PW_CO_SELECT (   lhs,
  ... 
)     lhs = co_await ::pw::async2::internal::InPlaceSelectFuture(__VA_ARGS__)

Like PW_SELECT, but for use in coroutines.

PW_CO_SELECT suspends the coroutine until at least one of the futures completes, then assigns an OptionalTuple containing the outputs of every future that completed to lhs. Futures that did not complete stay pending and can be selected again.

The futures are referenced while the coroutine is suspended. This is safe for local variables of the coroutine, since coroutine frames never move. Like co_await on an lvalue future, other futures must outlive the PW_CO_SELECT and must not move while it is suspended.

Coro<Status> Relay(CoroContext,
Receiver<Msg>& rx,
TimeProvider<SystemClock>& time) {
auto deadline = time.WaitFor(5s); // One deadline for the whole loop.
auto next_msg = rx.Receive();
while (true) {
PW_CO_SELECT(auto result, next_msg, deadline);
if (result.has_value<1>()) {
co_return Status::DeadlineExceeded();
}
if (!result.value<0>().has_value()) {
co_return OkStatus(); // The channel closed.
}
Handle(*result.value<0>());
next_msg = rx.Receive(); // Re-arm only the future that completed.
}
}
#define PW_CO_SELECT(lhs,...)
Definition: select.h:291

◆ PW_SELECT

#define PW_SELECT (   lhs,
  cx,
  ... 
)     PW_TRY_READY_ASSIGN(lhs, ::pw::async2::internal::PendSelect(cx, __VA_ARGS__))

Waits for the first of several futures to complete, without taking ownership of them.

PW_SELECT pends each of the futures in place. If none of them have completed, it returns Pending() from the current function. Otherwise, it assigns an OptionalTuple containing the outputs of every future that completed to lhs.

Unlike Select, PW_SELECT leaves the futures with their owner. Futures that did not complete stay pending and can be selected again, so timers keep their deadlines and in-progress operations are not cancelled. Only re-arm the futures that completed.

  • The futures must be non-const lvalues, such as members of the task or composite future using PW_SELECT. They are only referenced while PW_SELECT runs, so their owner may be moved between polls.
  • Futures that are complete or were never armed are skipped, which disables their branch. At least one future must be pendable.
  • Check each element of the result with has_value<I>(). More than one future may complete at once.
  • PW_SELECT is a statement, not a future, so it can't be stored, returned, or passed to other combinators. Use Select when a future is needed, or call PW_SELECT from the Pend() function of a composite future.

For coroutines, use PW_CO_SELECT.

Poll<> DoPend(Context& cx) override {
while (true) {
if (!coin_future_.is_pendable()) {
coin_future_ = coin_slot_.GetCoins();
}
if (!key_future_.is_pendable()) {
key_future_ = keypad_.WaitForKeyPress();
}
PW_SELECT(auto result, cx, coin_future_, key_future_);
if (result.has_value<0>()) {
coins_ += result.value<0>();
}
if (result.has_value<1>()) {
HandleKeyPress(result.value<1>());
}
}
}
#define PW_SELECT(lhs, cx,...)
Definition: select.h:257

Function Documentation

◆ Join()

template<typename... Futures>
constexpr auto pw::async2::Join ( Futures &&...  futures)
constexpr

Creates a future which pends the provided futures until all of them have completed.

When ready, the resulting future returns a tuple containing each future's output in the order the futures were provided.

◆ Select()

template<typename... Futures>
SelectFuture< Futures... > pw::async2::Select ( Futures &&...  futures)

Runs each of the provided futures, resolving once the first has completed.

As additional futures may have completed during the time between the first completion and the task running, Select returns a Future<OptionalTuple> which stores the results of all the sub-futures which managed to complete.

Select takes ownership of its futures and destroys all of them once it completes, including those that did not complete. To wait on the same futures repeatedly, such as in a loop, use PW_SELECT or PW_CO_SELECT.