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)
|
DispatcherBound< T >
Constructs a |DispatcherBound
|
MakeTestDispatcherBound(async_dispatcher_t *dispatcher, Args &&... args)
|
TestDispatcherBound< T >
|
Classes |
|
---|---|
async_patterns:: |
An asynchronous |Callback| that will always execute on the async dispatcher associated with a |Receiver|. |
async_patterns:: |
|DispatcherBound |
async_patterns:: |
An asynchronous |Function| that will always execute on the async dispatcher associated with a |Receiver|. |
async_patterns:: |
This type is usually returned from a |DispatcherBound::AsyncCall| or calling |Callback |
async_patterns:: |
|TaskScope| lets you post asynchronous tasks that are silently discarded when the |TaskScope| object is destroyed. |
async_patterns:: |
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
See |DispatcherBound| constructor for details.
MakeTestDispatcherBound
TestDispatcherBound< T > MakeTestDispatcherBound( async_dispatcher_t *dispatcher, Args &&... args )