== Executors Since everything is asynchronous the library needs to use an event-loop. Because everything is single-threaded, it can be assumed that there is exactly one executor per thread, which will suffice for 97% of use-cases. Therefore, there is a `thread_local` executor that gets used as default by the coroutine objects (although stored by copy in the coroutine promise). Likewise, there is one `executor` type used by the library, which defaults to `asio::any_io_executor`. NOTE: If you write your own coroutine, it should hold a copy of the executor, and have a `get_executor` function returning it by const reference. === Using Strands While strands can be used, they are not compatible with the `thread_local` executor. This is because they might switch threads, thus they can't be `thread_local`. If you wish to use strands (e.g. through a <>) the executor for any <>, <> or <> must be assigned manually. In the case of a <> this is a constructor argument, but for the other coroutine types, `asio::executor_arg` needs to be used. This is done by having `asio::executor_arg_t` (somewhere) in the argument list directly followed by the executor to be used in the argument list of the coroutine, e.g.: [source,cpp] ---- cobalt::promise example_with_executor(int some_arg, asio::executor_arg_t, cobalt::executor); ---- This way the coroutine-promise can pick up the executor from the third argument, instead of defaulting to the thread_local one. The arguments can of course be defaulted, to make them less inconvenient, if they are sometimes with a thread_local executor. [source,cpp] ---- cobalt::promise example_with_executor(int some_arg, asio::executor_arg_t = asio::executor_arg, cobalt::executor = cobalt::this_thread::get_executor()); ---- If this gets omitted on a strand an exception of type `asio::bad_allocator` is thrown, or - worse - the wrong executor is used. == polymorphic memory resource Similarly, the library uses a thread_local `pmr::memory_resource` to allocate coroutine frames & to use as allocator on asynchronous operations. The reason is, that users may want to customize allocations, e.g. to avoid locks, limit memory usage or monitor usage. `pmr` allows us to achieve this without introducing unnecessary template parameters, i.e. no `promise` complexity. Using `pmr` however does introduce some minimal overheads, so a user has the option to disable by defining `BOOST_COBALT_NO_PMR`. <> uses an internal resource optimized for asio's allocator usages and <>, <> and <> use a monotonic resource to miminize allocations. Both still work with `BOOST_COBALT_NO_PMR` defined, in which case they'll use `new/delete` as upstream allocations. <> and <> single `pmr::unsynchronized_pool_resource` per thread with PMR enabled. NOTE: If you write your own coroutine, it should have a get_allocator function returning a `pmr::polymorphic_allocator`. == cancellation cobalt uses implicit cancellation based on `asio::cancellation_signal`. This is mostly used implicitly (e.g. with <>), so that there is very little explicit use in the examples. NOTE: If you write custom coroutine it must return a `cancellation_slot` from a `get_cancellation_slot` function in order to be able to cancel other operations. NOTE: If you write a custom awaitable, it can use that function in await_suspend to receive cancellation signals.