async_patterns

Summary

Functions

BindForSending(Callable callable, Args &&... args)
auto
|BindForSending| function packages up |args| so that they may be later executed as arguments to |callable| in a different execution context, asynchronously and possibly concurrently.
MakeDispatcherBound(async_dispatcher_t *dispatcher, Args &&... args)
Constructs a |DispatcherBound| that holds an instance of |T| by sending the |args| to the constructor of |T| run from a |dispatcher| task.
MakeTestDispatcherBound(async_dispatcher_t *dispatcher, Args &&... args)

Classes

async_patterns::Callback< ReturnType(Args...)>

An asynchronous |Callback| that will always execute on the async dispatcher associated with a |Receiver|.

async_patterns::DispatcherBound

|DispatcherBound| enables an owner object living on some arbitrary thread, to construct, call methods on, and destroy an object of type |T| that must be used from a particular [synchronized async dispatcher][synchronized-dispatcher].

async_patterns::Function< ReturnType(Args...)>

An asynchronous |Function| that will always execute on the async dispatcher associated with a |Receiver|.

async_patterns::PendingCall

This type is usually returned from a |DispatcherBound::AsyncCall| or calling |Callback|.

async_patterns::TaskScope

|TaskScope| lets you post asynchronous tasks that are silently discarded when the |TaskScope| object is destroyed.

async_patterns::TestDispatcherBound

Functions

BindForSending

auto BindForSending(
  Callable callable,
  Args &&... args
)

|BindForSending| function packages up |args| so that they may be later executed as arguments to |callable| in a different execution context, asynchronously and possibly concurrently.

This is called "sending". For example, |DispatcherBound| uses |BindForSending| to send arguments to the object owned by |DispatcherBound|, as part of asynchronously calling their member functions.

It is similar to |std::bind_front|, but will first forward the |args| into the capture state of the resulting lambda, and then move the captured args into |callable| when invoked later.

Safety of sending arguments

Because the |args| are used at a later time, one needs to be aware of risks of use-after-free and data races. There are also the following restrictions:

  • When sending a ref-counted pointer such as |std::shared_ptr|, both the sender and the |callable| will be able to concurrently access |Arg|. Be sure to add appropriate synchronization to |Arg|, for example protecting fields with mutexes. This pattern is called "shared-state concurrency".
  • Value types may be sent via copying or moving. Whether one passes an |Arg|, |const Arg&|, or |Arg&&| etc on the sending side, the |callable| will have its own uniquely owned instance that they may safely manipulate.
  • Move-only types such as |std::unique_ptr| may be sent via |std::move|.
  • The |callable| may not take raw pointer or non-const reference arguments. Sending those may result in use-after-frees when the callable uses a pointee asynchronously after an unspecified amount of time. It's not worth the memory safety risks to support the cases where a pointee outlives the dispatcher that is running tasks for |T|.
  • If the |callable| takes |const Arg&| as an argument, one may send an instance of |Arg| via copying or moving. The instance will live until the callable finishes executing.
  • These checks are performed for each argument, but there could still be raw pointers or references inside an object that is sent. One must ensure that the pointee remain alive until the asynchronous tasks are run, possibly indefinitely until the dispatcher is destroyed.

MakeDispatcherBound

DispatcherBound< T > MakeDispatcherBound(
  async_dispatcher_t *dispatcher,
  Args &&... args
)

Constructs a |DispatcherBound| that holds an instance of |T| by sending the |args| to the constructor of |T| run from a |dispatcher| task.

See |DispatcherBound| constructor for details.

MakeTestDispatcherBound

TestDispatcherBound< T > MakeTestDispatcherBound(
  async_dispatcher_t *dispatcher,
  Args &&... args
)