blob: 1649fd3b68090a27c2f7349d6f50a3b872d8ad32 [file] [log] [blame]
/ Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at
[section:std_executors Proposed Standard Executors]
Asio provides a complete implementation of the proposed standard executors, as
described in [@ P0443r13], [@
P1348r0], and [@ P1393r0].
Just as with executors under the Networking TS model, a standard executor
represents a policy as to how, when, and where a piece of code should be
executed. Most existing code should continue to work with little or no change.
[heading Standard Executor Implementations in Asio]
The [link asio.reference.io_context.executor_type `io_context::executor_type`],
[link asio.reference.thread_pool.executor_type `thread_pool::executor_type`],
[link asio.reference.system_executor `system_executor`], and [link
asio.reference.strand `strand`] executors meet the requirements for the
proposed standard executors. For compatibility, these classes also meet the
requirements for the Networking TS model of executors.
[heading Standard Executor Use in Asio]
All I/O objects such as [link asio.reference.ip__tcp.socket `ip::tcp::socket`],
asynchronous operations, and utilities including [link asio.reference.dispatch
`dispatch`], [link `post`], [link asio.reference.defer
`defer`], [link asio.reference.get_associated_executor
`get_associated_executor`], [link asio.reference.bind_executor
`bind_executor`], [link asio.reference.make_work_guard `make_work_guard`],
[link asio.reference.spawn `spawn`], [link asio.reference.co_spawn `co_spawn`],
[link asio.reference.async_compose `async_compose`], [link
asio.reference.use_future `use_future`], etc., can interoperate with both
proposed standard executors, and with Networking TS executors. Asio's
implementation determines at compile time which model a particular executor
meets; the proposed standard executor model is used in preference if both are
Support for the existing Networking TS model of executors can be disabled
by defining `ASIO_NO_TS_EXECUTORS`.
[heading Polymorphic I/O Executor]
The [link asio.reference.any_io_executor `any_io_executor`] type alias is the
default runtime-polymorphic executor for all I/O objects. This type alias
points to the [link asio.reference.execution__any_executor
`execution::any_executor<>`] template with a set of supportable properties
specified for use with I/O.
This new name may break existing code that directly uses the old polymorphic
wrapper, [link asio.reference.executor `executor`]. If required for backward
compatibility, `ASIO_USE_TS_EXECUTOR_AS_DEFAULT` can be defined, which changes
the `any_io_executor` type alias to instead point to the `executor` polymorphic
[heading Implementing a Minimal I/O Executor]
Standard executor properties make what were previously hard requirements on an
executor (such as work counting, or the ability to distinguish between `post`,
`dispatch`, and `defer`) into optional facilities. With this relaxation, the
minimal requirements for an I/O executor are:
* Conformance to the [link asio.reference.Executor1.standard_executors
`executor`] concept.
* The ability to query the [link asio.reference.execution__context
`execution::context`] property, with the result being [link
asio.reference.execution_context `execution_context&`] or a reference to a
class that is derived from `execution_context`.
* The `execute` operation having, at minimum, the [link
asio.reference.execution__blocking_t.never `execution::blocking.never`]
The following example shows a minimal I/O executor. Given a queue submission
operation implemented elsewhere:
queue_t queue_create();
template <typename F> void queue_submit(queue_t q, F f);
the executor may be defined as follows:
struct minimal_io_executor
asio::execution_context* context_;
queue_t queue_;
bool operator==(const minimal_io_executor& other) const noexcept
return context_ == other.context_ && queue_ == other.queue_;
bool operator!=(const minimal_io_executor& other) const noexcept
return !(*this == other);
asio::execution_context& query(
asio::execution::context_t) const noexcept
return *context_;
static constexpr asio::execution::blocking_t::never_t query(
asio::execution::blocking_t) noexcept
// This executor always has blocking.never semantics.
return asio::execution::blocking.never;
template <class F>
void execute(F f) const
queue_submit(queue_, std::move(f));
This executor may be created as follows:
asio::execution_context context;
queue_t queue = queue_create();
minimal_io_executor executor{&context, queue};
and then used with I/O objects:
asio::ip::tcp::acceptor acceptor(executor);
or assigned into the [link asio.reference.any_io_executor `any_io_executor`]
polymorphic wrapper:
asio::any_io_executor poly_executor = executor;
[heading Traits for Deducing Conformance to the Executor Concept]
Older C++ standards and compilers require some assistance to determine whether
an executor implementation conforms to the `executor` concept and type
requirements. This is achieved through specialisation of traits. The following
code shows a specialisation of these traits for the `minimal_io_executor`
example from above:
namespace asio {
namespace traits {
template <typename F>
struct execute_member<minimal_io_executor, F>
static constexpr bool is_valid = true;
static constexpr bool is_noexcept = true;
typedef void result_type;
template <>
struct equality_comparable<minimal_io_executor>
static constexpr bool is_valid = true;
static constexpr bool is_noexcept = true;
template <>
struct query_member<minimal_io_executor,
static constexpr bool is_valid = true;
static constexpr bool is_noexcept = true;
typedef asio::execution_context& result_type;
template <typename Property>
struct query_static_constexpr_member<minimal_io_executor, Property,
typename enable_if<
std::is_convertible<Property, asio::execution::blocking_t>::value
static constexpr bool is_valid = true;
static constexpr bool is_noexcept = true;
typedef asio::execution::blocking_t::never_t result_type;
static constexpr result_type value() noexcept { return result_type(); }
} // namespace traits
} // namespace asio
Asio uses an extensive set of traits to implement all of the proposed standard
executor functionality on older C++ standards. These traits may be found under
the [^asio/traits] include directory.