| [/ |
| / 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 http://www.boost.org/LICENSE_1_0.txt) |
| /] |
| |
| [section:Executor1 Executor requirements] |
| |
| [heading 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) { |
| 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 `asio::query(x1,p) == asio::query(x2,p)` |
| for every property `p` where both `asio::query(x1,p)` and `asio::query(x2,p)` |
| are well-formed and result in a non-void type that is `equality_comparable` |
| (C++Std [equalitycomparable]). [inline_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 `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.] |
| |
| An executor type's destructor shall not block pending completion of the |
| submitted function objects. [inline_note The ability to wait for completion of |
| submitted function objects may be provided by the associated execution |
| context.] |
| |
| 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)`: |
| |
| * Evaluates `DECAY_COPY(std::forward<F>(f))` on the calling thread to create |
| `cf` that will be invoked at most once by an execution agent. |
| |
| * May block pending completion of this invocation. Synchronizes with |
| [intro.multithread] the invocation of `f`. |
| |
| * Shall not propagate any exception thrown by the function object or any other |
| function submitted to the executor. |
| |
| [inline_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.] |
| |
| [heading 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. [inline_note The copy constructor, comparison operators, and |
| `context()` member function continue to remain valid until `ctx` is destroyed.] |
| |
| 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 Executor requirements |
| [[expression] [type] [assertion/note[br]pre/post-conditions]] |
| [ |
| [`X u(x1);`] |
| [] |
| [Shall not exit via an exception.[br] |
| [br] |
| post: `u == x1` and |
| `std::addressof(u.context()) == std::addressof(x1.context()).`] |
| ] |
| [ |
| [`X u(mx1);`] |
| [] |
| [Shall not exit via an exception.[br] |
| [br] |
| 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. |
| [inline_note Returning `false` does not necessarily imply that the effects |
| are not identical.][br] |
| [br] |
| `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 |
| [link asio.reference.ExecutionContext `ExecutionContext`] requirements.] |
| [Shall not exit via an exception.[br] |
| [br] |
| 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.[br] |
| [br] |
| 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.[br] |
| [br] |
| 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. |
| [inline_note Executors defined in this Technical Specification always use |
| the supplied allocator unless otherwise specified.][br] |
| [br] |
| Synchronization: The invocation of `dispatch` synchronizes with (C++Std |
| \[intro.multithread\]) the invocation of `f1`.] |
| ] |
| [ |
| [`x1.post(std::move(f),a)`[br] |
| `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()`.[br] |
| [br] |
| 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. |
| [inline_note Executors defined in this Technical Specification always use |
| the supplied allocator unless otherwise specified.][br] |
| [br] |
| Synchronization: The invocation of `post` or `defer` synchronizes with |
| (C++Std \[intro.multithread\]) the invocation of `f1`.[br] |
| [br] |
| [inline_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.]] |
| ] |
| ] |
| |
| [endsect] |