• 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:asynchronous_operations Requirements on asynchronous operations]
9
10This section uses the names `Alloc1`, `Alloc2`, `alloc1`, `alloc2`, `Args`,
11`CompletionHandler`, `completion_handler`, `Executor1`, `Executor2`, `ex1`,
12`ex2`, `f`, [^['i]], [^['N]], `Signature`, `token`, [^T[sub ['i]]], [^t[sub
13['i]]], `work1`, and `work2` as placeholders for specifying the requirements
14below.
15
16[heading General asynchronous operation concepts]
17
18An ['initiating function] is a function which may be called to start an
19asynchronous operation. A ['completion handler] is a function object that will
20be invoked, at most once, with the result of the asynchronous operation.
21
22The lifecycle of an asynchronous operation is comprised of the following events
23and phases:
24
25[mdash] Event 1: The asynchronous operation is started by a call to the
26initiating function.
27
28[mdash] Phase 1: The asynchronous operation is now ['outstanding].
29
30[mdash] Event 2: The externally observable side effects of the asynchronous
31operation, if any, are fully established. The completion handler is submitted
32to an executor.
33
34[mdash] Phase 2: The asynchronous operation is now ['completed].
35
36[mdash] Event 3: The completion handler is called with the result of the
37asynchronous operation.
38
39In this library, all functions with the prefix `async_` are initiating
40functions.
41
42[heading Completion tokens and handlers]
43
44Initiating functions:
45
46[mdash] are function templates with template parameter `CompletionToken`;
47
48[mdash] accept, as the final parameter, a ['completion token] object `token`
49of type `CompletionToken`;
50
51[mdash] specify a ['completion signature], which is a call signature (C++Std
52[func.def]) `Signature` that determines the arguments to the completion
53handler.
54
55An initiating function determines the type `CompletionHandler` of its
56completion handler function object by performing `typename
57async_result<decay_t<CompletionToken>, Signature>::completion_handler_type`.
58The completion handler object `completion_handler` is initialized with
59`forward<CompletionToken>(token)`. [inline_note No other requirements are
60placed on the type `CompletionToken`.]
61
62The type `CompletionHandler` must satisfy the requirements of `Destructible`
63(C++Std [destructible]) and `MoveConstructible` (C++Std
64[moveconstructible]), and be callable with the specified call signature.
65
66In this library, all initiating functions specify a ['Completion signature]
67element that defines the call signature `Signature`. The ['Completion
68signature] elements in this Technical Specification have named parameters, and
69the results of an asynchronous operation are specified in terms of these names.
70
71[heading Automatic deduction of initiating function return type]
72
73The return type of an initiating function is `typename
74async_result<decay_t<CompletionToken>, Signature>::return_type`.
75
76For the sake of exposition, this library sometimes annotates functions with a
77return type ['[^DEDUCED]]. For every function declaration that returns
78['[^DEDUCED]], the meaning is equivalent to specifying the return type as
79`typename async_result<decay_t<CompletionToken>, Signature>::return_type`.
80
81[heading Production of initiating function return value]
82
83An initiating function produces its return type as follows:
84
85[mdash] constructing an object `result` of type
86`async_result<decay_t<CompletionToken>, Signature>`, initialized as
87`result(completion_handler)`; and
88
89[mdash] using `result.get()` as the operand of the return statement.
90
91\[['Example:] Given an asynchronous operation with ['Completion signature]
92`void(R1 r1, R2 r2)`, an initiating function meeting these requirements may be
93implemented as follows:
94
95  template<class CompletionToken>
96  auto async_xyz(T1 t1, T2 t2, CompletionToken&& token)
97  {
98    typename async_result<decay_t<CompletionToken>, void(R1, R2)>::completion_handler_type
99      completion_handler(forward<CompletionToken>(token));
100
101    async_result<decay_t<CompletionToken>, void(R1, R2)> result(completion_handler);
102
103    // initiate the operation and cause completion_handler to be invoked with
104    // the result
105
106    return result.get();
107  }
108
109For convenience, initiating functions may be implemented using the
110`async_completion` template:
111
112  template<class CompletionToken>
113  auto async_xyz(T1 t1, T2 t2, CompletionToken&& token)
114  {
115    async_completion<CompletionToken, void(R1, R2)> init(token);
116
117    // initiate the operation and cause init.completion_handler to be invoked
118    // with the result
119
120    return init.result.get();
121  }
122
123'''&mdash;'''['end example]\]
124
125[heading Lifetime of initiating function arguments]
126
127Unless otherwise specified, the lifetime of arguments to initiating functions
128shall be treated as follows:
129
130[mdash] If the parameter has a pointer type or has a type of lvalue reference
131to non-const, the implementation may assume the validity of the pointee or
132referent, respectively, until the completion handler is invoked. [inline_note
133In other words, the program must guarantee the validity of the argument until
134the completion handler is invoked.]
135
136[mdash] Otherwise, the implementation must not assume the validity of the
137argument after the initiating function completes. [inline_note In other words,
138the program is not required to guarantee the validity of the argument after the
139initiating function completes.] The implementation may make copies of the
140argument, and all copies shall be destroyed no later than immediately after
141invocation of the completion handler.
142
143[heading Non-blocking requirements on initiating functions]
144
145An initiating function shall not block (C++Std [defns.block]) the calling
146thread pending completion of the outstanding operation.
147
148[std_note Initiating functions may still block the calling thread for other
149reasons. For example, an initiating function may lock a mutex in order to
150synchronize access to shared data.]
151
152[heading Associated executor]
153
154Certain objects that participate in asynchronous operations have an
155['associated executor]. These are obtained as specified in the sections below.
156
157[heading Associated I/O executor]
158
159An asynchronous operation has an associated executor satisfying the [link
160boost_asio.reference.Executor1 `Executor`] requirements. If not otherwise specified by
161the asynchronous operation, this associated executor is an object of type
162`system_executor`.
163
164All asynchronous operations in this library have an associated executor object
165that is determined as follows:
166
167[mdash] If the initiating function is a member function, the associated
168executor is that returned by the `get_executor` member function on the same
169object.
170
171[mdash] If the initiating function is not a member function, the associated
172executor is that returned by the `get_executor` member function of the first
173argument to the initiating function.
174
175Let `Executor1` be the type of the associated executor. Let `ex1` be a value of
176type `Executor1`, representing the associated executor object obtained as
177described above.
178
179[heading Associated completion handler executor]
180
181A completion handler object of type `CompletionHandler` has an associated
182executor of type `Executor2` satisfying the [link boost_asio.reference.Executor1
183Executor requirements]. The type `Executor2` is
184`associated_executor_t<CompletionHandler, Executor1>`. Let `ex2` be a value of
185type `Executor2` obtained by performing
186`get_associated_executor(completion_handler, ex1)`.
187
188[heading Outstanding work]
189
190Until the asynchronous operation has completed, the asynchronous operation
191shall maintain:
192
193[mdash] an object `work1` of type `executor_work_guard<Executor1>`, initialized
194as `work1(ex1)`, and where `work1.owns_work() == true`; and
195
196[mdash] an object `work2` of type `executor_work_guard<Executor2>`, initialized
197as `work2(ex2)`, and where `work2.owns_work() == true`.
198
199[heading Allocation of intermediate storage]
200
201Asynchronous operations may allocate memory. [inline_note Such as a data
202structure to store copies of the `completion_handler` object and the initiating
203function's arguments.]
204
205Let `Alloc1` be a type, satisfying the [link boost_asio.reference.ProtoAllocator
206`ProtoAllocator`] requirements, that represents the asynchronous operation's
207default allocation strategy. [inline_note Typically `std::allocator<void>`.]
208Let `alloc1` be a value of type `Alloc1`.
209
210A completion handler object of type `CompletionHandler` has an associated
211allocator object `alloc2` of type `Alloc2` satisfying the [link
212boost_asio.reference.ProtoAllocator `ProtoAllocator`] requirements. The type `Alloc2`
213is `associated_allocator_t<CompletionHandler, Alloc1>`. Let `alloc2` be a value
214of type `Alloc2` obtained by performing
215`get_associated_allocator(completion_handler, alloc1)`.
216
217The asynchronous operations defined in this library:
218
219[mdash] If required, allocate memory using only the completion handler's
220associated allocator.
221
222[mdash] Prior to completion handler execution, deallocate any memory allocated
223using the completion handler's associated allocator.
224
225[std_note The implementation may perform operating system or underlying API
226calls that perform memory allocations not using the associated allocator.
227Invocations of the allocator functions may not introduce data races (See C++Std
228\[res.on.data.races\]).]
229
230[heading Execution of completion handler on completion of asynchronous operation]
231
232Let `Args...` be the argument types of the completion signature `Signature` and
233let [^['N]] be `sizeof...(Args)`. Let [^['i]] be in the range [half_open_range
234`0`,[^['N]]]. Let [^T[sub ['i]]] be the [^['i]]th type in `Args...` and let
235[^t[sub ['i]]] be the [^['i]]th completion handler argument associated with
236[^T[sub ['i]]].
237
238Let `f` be a function object, callable as `f()`, that invokes
239`completion_handler` as if by [^completion_handler(forward<T[sub ['0]]>(t[sub
240['0]]), ..., forward<T[sub ['N-1]]>(t[sub ['N-1]]))].
241
242If an asynchonous operation completes immediately (that is, within the thread
243of execution calling the initiating function, and before the initiating
244function returns), the completion handler shall be submitted for execution as
245if by performing `ex2.post(std::move(f), alloc2)`. Otherwise, the completion
246handler shall be submitted for execution as if by performing
247`ex2.dispatch(std::move(f), alloc2)`.
248
249[heading Completion handlers and exceptions]
250
251Completion handlers are permitted to throw exceptions. The effect of any
252exception propagated from the execution of a completion handler is determined
253by the executor which is executing the completion handler.
254
255[heading Default completion tokens]
256
257Every I/O executor type has an associated default completion token type. This is
258specified via the `default_completion_token` trait. This trait may be used in
259asynchronous operation declarations as follows:
260
261  template <
262      typename IoObject,
263      typename CompletionToken =
264        typename default_completion_token<
265          typename IoObject::executor_type
266        >::type
267    >
268  auto async_xyz(
269      IoObject& io_object,
270      CompletionToken&& token =
271        typename default_completion_token<
272          typename IoObject::executor_type
273        >::type{}
274    );
275
276If not specialised, this trait type is `void`, meaning no default completion
277token type is available for the given I/O executor.
278
279\[['Example:] The `default_completion_token` trait is specialised for the
280`use_awaitable` completion token so that it may be used as shown in the
281following example:
282
283  auto socket = use_awaitable.as_default_on(tcp::socket(my_context));
284  // ...
285  co_await socket.async_connect(my_endpoint); // Defaults to use_awaitable.
286
287In this example, the type of the `socket` object is transformed from
288`tcp::socket` to have an I/O executor with the default completion token set to
289`use_awaitable`.
290
291Alternatively, the socket type may be computed directly:
292
293  using tcp_socket = use_awaitable_t<>::as_default_on_t<tcp::socket>;
294  tcp_socket socket(my_context);
295  // ...
296  co_await socket.async_connect(my_endpoint); // Defaults to use_awaitable.
297
298'''&mdash;'''['end example]\]
299
300[endsect]
301