...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Let executor-of-impl
be the exposition-only concept
template<class E, class F> concept executor-of-impl = invocable<decay_t<F>&> && constructible_from<decay_t<F>, F> && move_constructible<decay_t<F>> && copy_constructible<E> && is_nothrow_copy_constructible_v<E> && equality_comparable<E> /* nothrow */ && requires(const E& e, F&& f) { execution::execute(e, (F&&)f); };
Then the executor
and executor_of
concepts are
defined as follows:
template<class E> concept executor = executor-of-impl<E, execution::invocable_archetype>; template<class E, class F> concept executor_of = executor<E> && executor-of-impl<E, F>;
Neither an executor's equality comparison nor swap
operation
shall exit via an exception.
None of an executor type's copy constructor, destructor, equality comparison,
swap
function, execute
function, or associated
query
functions shall introduce data races as a result of concurrent
invocations of those functions from different threads.
For any two (possibly const) values x1
and x2
of
some executor type X
, x1 == x2
shall return true
only if boost::asio::query(x1,p) == boost::asio::query(x2,p)
for every property p
where both boost::asio::query(x1,p)
and boost::asio::query(x2,p)
are well-formed and result in a
non-void type that is equality_comparable
(C++Std [equalitycomparable]).
[Note: The above requirements imply that x1 ==
x2
returns true
if x1
and x2
can be interchanged with identical effects. An executor may conceptually
contain additional properties which are not exposed by a named property type
that can be observed via boost::asio::query
; in this case, it
is up to the concrete executor implementation to decide if these properties
affect equality. Returning false
does not necessarily imply
that the effects are not identical. —end note]
An executor type's destructor shall not block pending completion of the submitted function objects. [Note: The ability to wait for completion of submitted function objects may be provided by the associated execution context. —end note]
In addition to the above requirements, types E
and F
model executor_of
only if they satisfy the requirements of the
Table below.
Let:
e
denotes a (possibly const) executor object of type E
,
cf
denotes the function object DECAY_COPY(std::forward<F>(f))
f
denotes a function of type F&&
invocable
as cf()
and where decay_t<F>
models
move_constructible
.
The expression execution::execute(e, f)
:
DECAY_COPY(std::forward<F>(f))
on the calling
thread to create cf
that will be invoked at most once by
an execution agent.
f
.
[Note: The treatment of exceptions thrown by one-way submitted functions is implementation-defined. The forward progress guarantee of the associated execution agent(s) is implementation-defined. —end note]
The library describes a standard set of requirements for executors.
A type meeting the Executor
requirements embodies a set of rules
for determining how submitted function objects are to be executed.
A type X
meets the Executor
requirements if it
satisfies the requirements of CopyConstructible
(C++Std [copyconstructible])
and Destructible
(C++Std [destructible]), as well as the additional
requirements listed below.
No constructor, comparison operator, copy operation, move operation, swap
operation, or member functions context
, on_work_started
,
and on_work_finished
on these types shall exit via an exception.
The executor copy constructor, comparison operators, and other member functions defined in these requirements shall not introduce data races as a result of concurrent calls to those functions from different threads.
Let ctx
be the execution context returned by the executor's
context()
member function. An executor becomes invalid
when the first call to ctx.shutdown()
returns. The effect of
calling on_work_started
, on_work_finished
, dispatch
,
post
, or defer
on an invalid executor is undefined.
[Note: The copy constructor, comparison operators, and
context()
member function continue to remain valid until ctx
is destroyed. —end note]
In the table below, x1
and x2
denote (possibly
const) values of type X
, mx1
denotes an xvalue
of type X
, f
denotes a MoveConstructible
(C++Std [moveconstructible]) function object callable with zero arguments,
a
denotes a (possibly const) value of type A
meeting
the Allocator
requirements (C++Std [allocator.requirements]),
and u
denotes an identifier.
Table 18. Executor requirements
expression |
type |
assertion/note |
---|---|---|
|
Shall not exit via an exception. |
|
|
Shall not exit via an exception. |
|
|
|
Returns |
|
|
Same as |
|
|
Shall not exit via an exception. |
|
Shall not exit via an exception. |
|
|
Shall not exit via an exception. |
|
|
Effects: Creates an object |
|
|
Effects: Creates an object |