• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1[/
2 / Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
3 /
4 / Distributed under the Boost Software License, Version 1.0. (See accompanying
5 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 /]
7
8[section:Executor1 Executor requirements]
9
10[heading Standard executors]
11
12Let `executor-of-impl` be the exposition-only concept
13
14    template<class E, class F>
15      concept executor-of-impl =
16        invocable<decay_t<F>&> &&
17        constructible_from<decay_t<F>, F> &&
18        move_constructible<decay_t<F>> &&
19        copy_constructible<E> &&
20        is_nothrow_copy_constructible_v<E> &&
21        equality_comparable<E> /* nothrow */ &&
22        requires(const E& e, F&& f) {
23          execution::execute(e, (F&&)f);
24        };
25
26Then the `executor` and `executor_of` concepts are defined as follows:
27
28    template<class E>
29      concept executor =
30        executor-of-impl<E, execution::invocable_archetype>;
31
32    template<class E, class F>
33      concept executor_of =
34        executor<E> &&
35        executor-of-impl<E, F>;
36
37Neither an executor's equality comparison nor `swap` operation shall exit via
38an exception.
39
40None of an executor type's copy constructor, destructor, equality comparison,
41`swap` function, `execute` function, or associated `query` functions shall
42introduce data races as a result of concurrent invocations of those functions
43from different threads.
44
45For any two (possibly const) values `x1` and `x2` of some executor type `X`,
46`x1 == x2` shall return `true` only if `boost::asio::query(x1,p) == boost::asio::query(x2,p)`
47for every property `p` where both `boost::asio::query(x1,p)` and `boost::asio::query(x2,p)`
48are well-formed and result in a non-void type that is `equality_comparable`
49(C++Std [equalitycomparable]). [inline_note The above requirements imply that `x1
50== x2` returns `true` if `x1` and `x2` can be interchanged with identical
51effects. An executor may conceptually contain additional properties which are
52not exposed by a named property type that can be observed via `boost::asio::query`; in
53this case, it is up to the concrete executor implementation to decide if these
54properties affect equality. Returning `false` does not necessarily imply that
55the effects are not identical.]
56
57An executor type's destructor shall not block pending completion of the
58submitted function objects. [inline_note The ability to wait for completion of
59submitted function objects may be provided by the associated execution
60context.]
61
62In addition to the above requirements, types `E` and `F` model `executor_of`
63only if they satisfy the requirements of the Table below.
64
65Let:
66
67* `e` denotes a (possibly const) executor object of type `E`,
68
69* `cf` denotes the function object `DECAY_COPY(std::forward<F>(f))`
70
71* `f` denotes a function of type `F&&` invocable as `cf()` and where
72  `decay_t<F>` models `move_constructible`.
73
74The expression `execution::execute(e, f)`:
75
76* Evaluates `DECAY_COPY(std::forward<F>(f))` on the calling thread to create
77  `cf` that will be invoked at most once by an execution agent.
78
79* May block pending completion of this invocation. Synchronizes with
80  [intro.multithread] the invocation of `f`.
81
82* Shall not propagate any exception thrown by the function object or any other
83  function submitted to the executor.
84
85[inline_note The treatment of exceptions thrown by one-way submitted functions
86is implementation-defined. The forward progress guarantee of the associated
87execution agent(s) is implementation-defined.]
88
89[heading Networking TS-style executors]
90
91The library describes a standard set of requirements for ['executors]. A type
92meeting the `Executor` requirements embodies a set of rules for determining how
93submitted function objects are to be executed.
94
95A type `X` meets the `Executor` requirements if it satisfies the requirements of
96`CopyConstructible` (C++Std [copyconstructible]) and `Destructible` (C++Std
97[destructible]), as well as the additional requirements listed below.
98
99No constructor, comparison operator, copy operation, move operation, swap
100operation, or member functions `context`, `on_work_started`, and
101`on_work_finished` on these types shall exit via an exception.
102
103The executor copy constructor, comparison operators, and other member functions
104defined in these requirements shall not introduce data races as a result of
105concurrent calls to those functions from different threads.
106
107Let `ctx` be the execution context returned by the executor's `context()`
108member function. An executor becomes ['invalid] when the first call to
109`ctx.shutdown()` returns. The effect of calling `on_work_started`,
110`on_work_finished`, `dispatch`, `post`, or `defer` on an invalid executor is
111undefined. [inline_note The copy constructor, comparison operators, and
112`context()` member function continue to remain valid until `ctx` is destroyed.]
113
114In the table below, `x1` and `x2` denote (possibly const) values of type `X`,
115`mx1` denotes an xvalue of type `X`, `f` denotes a `MoveConstructible` (C++Std
116[moveconstructible]) function object callable with zero arguments, `a` denotes
117a (possibly const) value of type `A` meeting the `Allocator` requirements
118(C++Std [allocator.requirements]), and `u` denotes an identifier.
119
120[table Executor requirements
121  [[expression] [type] [assertion/note[br]pre/post-conditions]]
122  [
123    [`X u(x1);`]
124    []
125    [Shall not exit via an exception.[br]
126     [br]
127     post: `u == x1` and
128     `std::addressof(u.context()) == std::addressof(x1.context()).`]
129  ]
130  [
131    [`X u(mx1);`]
132    []
133    [Shall not exit via an exception.[br]
134     [br]
135     post: `u` equals the prior value of `mx1` and
136     `std::addressof(u.context())` equals the prior value of
137     `std::addressof(mx1.context())`.]
138  ]
139  [
140    [`x1 == x2`]
141    [`bool`]
142    [ Returns `true` only if `x1` and `x2` can be interchanged with identical
143     effects in any of the expressions defined in these type requirements.
144     [inline_note Returning `false` does not necessarily imply that the effects
145     are not identical.][br]
146     [br]
147     `operator==` shall be reflexive, symmetric, and transitive, and shall not
148     exit via an exception.]
149  ]
150  [
151    [`x1 != x2`]
152    [`bool`]
153    [Same as `!(x1 == x2)`.]
154  ]
155  [
156    [`x1.context()`]
157    [`execution_context&`, or `E&` where `E` is a type that satifisfies the
158     [link boost_asio.reference.ExecutionContext `ExecutionContext`] requirements.]
159    [Shall not exit via an exception.[br]
160     [br]
161     The comparison operators and member functions defined in these
162     requirements shall not alter the reference returned by this function.]
163  ]
164  [
165    [`x1.on_work_started()`]
166    []
167    [Shall not exit via an exception.]
168  ]
169  [
170    [`x1.on_work_finished()`]
171    []
172    [Shall not exit via an exception.[br]
173     [br]
174     Precondition: A preceding call `x2.on_work_started()` where `x1 == x2`.]
175  ]
176  [
177    [`x1.dispatch(std::move(f),a)`]
178    []
179    [Effects: Creates an object `f1` initialized with
180     [^['DECAY_COPY]]`(forward<Func>(f))` (C++Std \[thread.decaycopy\]) in the
181     current thread of execution . Calls `f1()` at most once. The executor may
182     block forward progress of the caller until `f1()` finishes execution.[br]
183     [br]
184     Executor implementations should use the supplied allocator to allocate any
185     memory required to store the function object. Prior to invoking the
186     function object, the executor shall deallocate any memory allocated.
187     [inline_note Executors defined in this Technical Specification always use
188     the supplied allocator unless otherwise specified.][br]
189     [br]
190     Synchronization: The invocation of `dispatch` synchronizes with (C++Std
191     \[intro.multithread\]) the invocation of `f1`.]
192  ]
193  [
194    [`x1.post(std::move(f),a)`[br]
195     `x1.defer(std::move(f),a)`]
196    []
197    [Effects: Creates an object `f1` initialized with
198     [^['DECAY_COPY]]`(forward<Func>(f))` in the current thread of execution.
199     Calls `f1()` at most once. The executor shall not block forward progress
200     of the caller pending completion of `f1()`.[br]
201     [br]
202     Executor implementations should use the supplied allocator to allocate any
203     memory required to store the function object. Prior to invoking the
204     function object, the executor shall deallocate any memory allocated.
205     [inline_note Executors defined in this Technical Specification always use
206     the supplied allocator unless otherwise specified.][br]
207     [br]
208     Synchronization: The invocation of `post` or `defer` synchronizes with
209     (C++Std \[intro.multithread\]) the invocation of `f1`.[br]
210     [br]
211     [inline_note Although the requirements placed on `defer` are identical to
212     `post`, the use of `post` conveys a preference that the caller ['does not]
213     block the first step of [^f1]'s progress, whereas `defer` conveys a
214     preference that the caller ['does] block the first step of [^f1]. One use
215     of `defer` is to convey the intention of the caller that [^f1] is a
216     continuation of the current call context. The executor may use this
217     information to optimize or otherwise adjust the way in which `f1` is
218     invoked.]]
219  ]
220]
221
222[endsect]
223