Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Executor requirements

Standard executors

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) {
      e.execute((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:

The expression e.execute(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]

Networking TS-style executors

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
pre/post-conditions

X u(x1);

Shall not exit via an exception.

post: u == x1 and std::addressof(u.context()) == std::addressof(x1.context()).

X u(mx1);

Shall not exit via an exception.

post: u equals the prior value of mx1 and std::addressof(u.context()) equals the prior value of std::addressof(mx1.context()).

x1 == x2

bool

Returns true only if x1 and x2 can be interchanged with identical effects in any of the expressions defined in these type requirements. [Note: Returning false does not necessarily imply that the effects are not identical. —end note]

operator== shall be reflexive, symmetric, and transitive, and shall not exit via an exception.

x1 != x2

bool

Same as !(x1 == x2).

x1.context()

execution_context&, or E& where E is a type that satifisfies the ExecutionContext requirements.

Shall not exit via an exception.

The comparison operators and member functions defined in these requirements shall not alter the reference returned by this function.

x1.on_work_started()

Shall not exit via an exception.

x1.on_work_finished()

Shall not exit via an exception.

Precondition: A preceding call x2.on_work_started() where x1 == x2.

x1.dispatch(std::move(f),a)

Effects: Creates an object f1 initialized with DECAY_COPY(forward<Func>(f)) (C++Std [thread.decaycopy]) in the current thread of execution . Calls f1() at most once. The executor may block forward progress of the caller until f1() finishes execution.

Executor implementations should use the supplied allocator to allocate any memory required to store the function object. Prior to invoking the function object, the executor shall deallocate any memory allocated. [Note: Executors defined in this Technical Specification always use the supplied allocator unless otherwise specified. —end note]

Synchronization: The invocation of dispatch synchronizes with (C++Std [intro.multithread]) the invocation of f1.

x1.post(std::move(f),a)
x1.defer(std::move(f),a)

Effects: Creates an object f1 initialized with DECAY_COPY(forward<Func>(f)) in the current thread of execution. Calls f1() at most once. The executor shall not block forward progress of the caller pending completion of f1().

Executor implementations should use the supplied allocator to allocate any memory required to store the function object. Prior to invoking the function object, the executor shall deallocate any memory allocated. [Note: Executors defined in this Technical Specification always use the supplied allocator unless otherwise specified. —end note]

Synchronization: The invocation of post or defer synchronizes with (C++Std [intro.multithread]) the invocation of f1.

[Note: Although the requirements placed on defer are identical to post, the use of post conveys a preference that the caller does not block the first step of f1's progress, whereas defer conveys a preference that the caller does block the first step of f1. One use of defer is to convey the intention of the caller that f1 is a continuation of the current call context. The executor may use this information to optimize or otherwise adjust the way in which f1 is invoked. —end note]



PrevUpHomeNext