2 / Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
8 [section:asynchronous_operations Requirements on asynchronous operations]
10 This 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
16 [heading General asynchronous operation concepts]
18 An ['initiating function] is a function which may be called to start an
19 asynchronous operation. A ['completion handler] is a function object that will
20 be invoked, at most once, with the result of the asynchronous operation.
22 The lifecycle of an asynchronous operation is comprised of the following events
25 [mdash] Event 1: The asynchronous operation is started by a call to the
28 [mdash] Phase 1: The asynchronous operation is now ['outstanding].
30 [mdash] Event 2: The externally observable side effects of the asynchronous
31 operation, if any, are fully established. The completion handler is submitted
34 [mdash] Phase 2: The asynchronous operation is now ['completed].
36 [mdash] Event 3: The completion handler is called with the result of the
37 asynchronous operation.
39 In this library, all functions with the prefix `async_` are initiating
42 [heading Completion tokens and handlers]
46 [mdash] are function templates with template parameter `CompletionToken`;
48 [mdash] accept, as the final parameter, a ['completion token] object `token`
49 of type `CompletionToken`;
51 [mdash] specify a ['completion signature], which is a call signature (C++Std
52 [func.def]) `Signature` that determines the arguments to the completion
55 An initiating function determines the type `CompletionHandler` of its
56 completion handler function object by performing `typename
57 async_result<decay_t<CompletionToken>, Signature>::completion_handler_type`.
58 The completion handler object `completion_handler` is initialized with
59 `forward<CompletionToken>(token)`. [inline_note No other requirements are
60 placed on the type `CompletionToken`.]
62 The 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.
66 In this library, all initiating functions specify a ['Completion signature]
67 element that defines the call signature `Signature`. The ['Completion
68 signature] elements in this Technical Specification have named parameters, and
69 the results of an asynchronous operation are specified in terms of these names.
71 [heading Automatic deduction of initiating function return type]
73 The return type of an initiating function is `typename
74 async_result<decay_t<CompletionToken>, Signature>::return_type`.
76 For the sake of exposition, this library sometimes annotates functions with a
77 return 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`.
81 [heading Production of initiating function return value]
83 An initiating function produces its return type as follows:
85 [mdash] constructing an object `result` of type
86 `async_result<decay_t<CompletionToken>, Signature>`, initialized as
87 `result(completion_handler)`; and
89 [mdash] using `result.get()` as the operand of the return statement.
91 \[['Example:] Given an asynchronous operation with ['Completion signature]
92 `void(R1 r1, R2 r2)`, an initiating function meeting these requirements may be
93 implemented as follows:
95 template<class CompletionToken>
96 auto async_xyz(T1 t1, T2 t2, CompletionToken&& token)
98 typename async_result<decay_t<CompletionToken>, void(R1, R2)>::completion_handler_type
99 completion_handler(forward<CompletionToken>(token));
101 async_result<decay_t<CompletionToken>, void(R1, R2)> result(completion_handler);
103 // initiate the operation and cause completion_handler to be invoked with
109 For convenience, initiating functions may be implemented using the
110 `async_completion` template:
112 template<class CompletionToken>
113 auto async_xyz(T1 t1, T2 t2, CompletionToken&& token)
115 async_completion<CompletionToken, void(R1, R2)> init(token);
117 // initiate the operation and cause init.completion_handler to be invoked
120 return init.result.get();
123 '''—'''['end example]\]
125 [heading Lifetime of initiating function arguments]
127 Unless otherwise specified, the lifetime of arguments to initiating functions
128 shall be treated as follows:
130 [mdash] If the parameter has a pointer type or has a type of lvalue reference
131 to non-const, the implementation may assume the validity of the pointee or
132 referent, respectively, until the completion handler is invoked. [inline_note
133 In other words, the program must guarantee the validity of the argument until
134 the completion handler is invoked.]
136 [mdash] Otherwise, the implementation must not assume the validity of the
137 argument after the initiating function completes. [inline_note In other words,
138 the program is not required to guarantee the validity of the argument after the
139 initiating function completes.] The implementation may make copies of the
140 argument, and all copies shall be destroyed no later than immediately after
141 invocation of the completion handler.
143 [heading Non-blocking requirements on initiating functions]
145 An initiating function shall not block (C++Std [defns.block]) the calling
146 thread pending completion of the outstanding operation.
148 [std_note Initiating functions may still block the calling thread for other
149 reasons. For example, an initiating function may lock a mutex in order to
150 synchronize access to shared data.]
152 [heading Associated executor]
154 Certain objects that participate in asynchronous operations have an
155 ['associated executor]. These are obtained as specified in the sections below.
157 [heading Associated I/O executor]
159 An asynchronous operation has an associated executor satisfying the [link
160 boost_asio.reference.Executor1 `Executor`] requirements. If not otherwise specified by
161 the asynchronous operation, this associated executor is an object of type
164 All asynchronous operations in this library have an associated executor object
165 that is determined as follows:
167 [mdash] If the initiating function is a member function, the associated
168 executor is that returned by the `get_executor` member function on the same
171 [mdash] If the initiating function is not a member function, the associated
172 executor is that returned by the `get_executor` member function of the first
173 argument to the initiating function.
175 Let `Executor1` be the type of the associated executor. Let `ex1` be a value of
176 type `Executor1`, representing the associated executor object obtained as
179 [heading Associated completion handler executor]
181 A completion handler object of type `CompletionHandler` has an associated
182 executor of type `Executor2` satisfying the [link boost_asio.reference.Executor1
183 Executor requirements]. The type `Executor2` is
184 `associated_executor_t<CompletionHandler, Executor1>`. Let `ex2` be a value of
185 type `Executor2` obtained by performing
186 `get_associated_executor(completion_handler, ex1)`.
188 [heading Outstanding work]
190 Until the asynchronous operation has completed, the asynchronous operation
193 [mdash] an object `work1` of type `executor_work_guard<Executor1>`, initialized
194 as `work1(ex1)`, and where `work1.owns_work() == true`; and
196 [mdash] an object `work2` of type `executor_work_guard<Executor2>`, initialized
197 as `work2(ex2)`, and where `work2.owns_work() == true`.
199 [heading Allocation of intermediate storage]
201 Asynchronous operations may allocate memory. [inline_note Such as a data
202 structure to store copies of the `completion_handler` object and the initiating
203 function's arguments.]
205 Let `Alloc1` be a type, satisfying the [link boost_asio.reference.ProtoAllocator
206 `ProtoAllocator`] requirements, that represents the asynchronous operation's
207 default allocation strategy. [inline_note Typically `std::allocator<void>`.]
208 Let `alloc1` be a value of type `Alloc1`.
210 A completion handler object of type `CompletionHandler` has an associated
211 allocator object `alloc2` of type `Alloc2` satisfying the [link
212 boost_asio.reference.ProtoAllocator `ProtoAllocator`] requirements. The type `Alloc2`
213 is `associated_allocator_t<CompletionHandler, Alloc1>`. Let `alloc2` be a value
214 of type `Alloc2` obtained by performing
215 `get_associated_allocator(completion_handler, alloc1)`.
217 The asynchronous operations defined in this library:
219 [mdash] If required, allocate memory using only the completion handler's
220 associated allocator.
222 [mdash] Prior to completion handler execution, deallocate any memory allocated
223 using the completion handler's associated allocator.
225 [std_note The implementation may perform operating system or underlying API
226 calls that perform memory allocations not using the associated allocator.
227 Invocations of the allocator functions may not introduce data races (See C++Std
228 \[res.on.data.races\]).]
230 [heading Execution of completion handler on completion of asynchronous operation]
232 Let `Args...` be the argument types of the completion signature `Signature` and
233 let [^['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
238 Let `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]]))].
242 If an asynchonous operation completes immediately (that is, within the thread
243 of execution calling the initiating function, and before the initiating
244 function returns), the completion handler shall be submitted for execution as
245 if by performing `ex2.post(std::move(f), alloc2)`. Otherwise, the completion
246 handler shall be submitted for execution as if by performing
247 `ex2.dispatch(std::move(f), alloc2)`.
249 [heading Completion handlers and exceptions]
251 Completion handlers are permitted to throw exceptions. The effect of any
252 exception propagated from the execution of a completion handler is determined
253 by the executor which is executing the completion handler.
255 [heading Default completion tokens]
257 Every I/O executor type has an associated default completion token type. This is
258 specified via the `default_completion_token` trait. This trait may be used in
259 asynchronous operation declarations as follows:
263 typename CompletionToken =
264 typename default_completion_token<
265 typename IoObject::executor_type
270 CompletionToken&& token =
271 typename default_completion_token<
272 typename IoObject::executor_type
276 If not specialised, this trait type is `void`, meaning no default completion
277 token type is available for the given I/O executor.
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
283 auto socket = use_awaitable.as_default_on(tcp::socket(my_context));
285 co_await socket.async_connect(my_endpoint); // Defaults to use_awaitable.
287 In 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
291 Alternatively, the socket type may be computed directly:
293 using tcp_socket = use_awaitable_t<>::as_default_on_t<tcp::socket>;
294 tcp_socket socket(my_context);
296 co_await socket.async_connect(my_endpoint); // Defaults to use_awaitable.
298 '''—'''['end example]\]