]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // |
b32b8144 FG |
2 | // io_context_strand.hpp |
3 | // ~~~~~~~~~~~~~~~~~~~~~ | |
7c673cae | 4 | // |
11fdf7f2 | 5 | // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
7c673cae FG |
6 | // |
7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
9 | // | |
10 | ||
b32b8144 FG |
11 | #ifndef BOOST_ASIO_IO_CONTEXT_STRAND_HPP |
12 | #define BOOST_ASIO_IO_CONTEXT_STRAND_HPP | |
7c673cae FG |
13 | |
14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) | |
15 | # pragma once | |
16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) | |
17 | ||
18 | #include <boost/asio/detail/config.hpp> | |
b32b8144 FG |
19 | |
20 | #if !defined(BOOST_ASIO_NO_EXTENSIONS) | |
21 | ||
7c673cae FG |
22 | #include <boost/asio/async_result.hpp> |
23 | #include <boost/asio/detail/handler_type_requirements.hpp> | |
24 | #include <boost/asio/detail/strand_service.hpp> | |
25 | #include <boost/asio/detail/wrapped_handler.hpp> | |
b32b8144 | 26 | #include <boost/asio/io_context.hpp> |
7c673cae FG |
27 | |
28 | #include <boost/asio/detail/push_options.hpp> | |
29 | ||
30 | namespace boost { | |
31 | namespace asio { | |
32 | ||
33 | /// Provides serialised handler execution. | |
34 | /** | |
b32b8144 | 35 | * The io_context::strand class provides the ability to post and dispatch |
7c673cae FG |
36 | * handlers with the guarantee that none of those handlers will execute |
37 | * concurrently. | |
38 | * | |
39 | * @par Order of handler invocation | |
40 | * Given: | |
41 | * | |
42 | * @li a strand object @c s | |
43 | * | |
44 | * @li an object @c a meeting completion handler requirements | |
45 | * | |
46 | * @li an object @c a1 which is an arbitrary copy of @c a made by the | |
47 | * implementation | |
48 | * | |
49 | * @li an object @c b meeting completion handler requirements | |
50 | * | |
51 | * @li an object @c b1 which is an arbitrary copy of @c b made by the | |
52 | * implementation | |
53 | * | |
54 | * if any of the following conditions are true: | |
55 | * | |
56 | * @li @c s.post(a) happens-before @c s.post(b) | |
57 | * | |
58 | * @li @c s.post(a) happens-before @c s.dispatch(b), where the latter is | |
59 | * performed outside the strand | |
60 | * | |
61 | * @li @c s.dispatch(a) happens-before @c s.post(b), where the former is | |
62 | * performed outside the strand | |
63 | * | |
64 | * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are | |
65 | * performed outside the strand | |
66 | * | |
67 | * then @c asio_handler_invoke(a1, &a1) happens-before | |
68 | * @c asio_handler_invoke(b1, &b1). | |
69 | * | |
70 | * Note that in the following case: | |
71 | * @code async_op_1(..., s.wrap(a)); | |
72 | * async_op_2(..., s.wrap(b)); @endcode | |
73 | * the completion of the first async operation will perform @c s.dispatch(a), | |
74 | * and the second will perform @c s.dispatch(b), but the order in which those | |
75 | * are performed is unspecified. That is, you cannot state whether one | |
76 | * happens-before the other. Therefore none of the above conditions are met and | |
77 | * no ordering guarantee is made. | |
78 | * | |
79 | * @note The implementation makes no guarantee that handlers posted or | |
80 | * dispatched through different @c strand objects will be invoked concurrently. | |
81 | * | |
82 | * @par Thread Safety | |
83 | * @e Distinct @e objects: Safe.@n | |
84 | * @e Shared @e objects: Safe. | |
85 | * | |
86 | * @par Concepts: | |
87 | * Dispatcher. | |
88 | */ | |
b32b8144 | 89 | class io_context::strand |
7c673cae FG |
90 | { |
91 | public: | |
92 | /// Constructor. | |
93 | /** | |
94 | * Constructs the strand. | |
95 | * | |
b32b8144 | 96 | * @param io_context The io_context object that the strand will use to |
7c673cae FG |
97 | * dispatch handlers that are ready to be run. |
98 | */ | |
b32b8144 | 99 | explicit strand(boost::asio::io_context& io_context) |
7c673cae | 100 | : service_(boost::asio::use_service< |
b32b8144 | 101 | boost::asio::detail::strand_service>(io_context)) |
7c673cae FG |
102 | { |
103 | service_.construct(impl_); | |
104 | } | |
105 | ||
106 | /// Destructor. | |
107 | /** | |
108 | * Destroys a strand. | |
109 | * | |
110 | * Handlers posted through the strand that have not yet been invoked will | |
111 | * still be dispatched in a way that meets the guarantee of non-concurrency. | |
112 | */ | |
113 | ~strand() | |
114 | { | |
115 | } | |
116 | ||
b32b8144 FG |
117 | #if !defined(BOOST_ASIO_NO_DEPRECATED) |
118 | /// (Deprecated: Use context().) Get the io_context associated with the | |
119 | /// strand. | |
120 | /** | |
121 | * This function may be used to obtain the io_context object that the strand | |
122 | * uses to dispatch handlers for asynchronous operations. | |
123 | * | |
124 | * @return A reference to the io_context object that the strand will use to | |
125 | * dispatch handlers. Ownership is not transferred to the caller. | |
126 | */ | |
127 | boost::asio::io_context& get_io_context() | |
128 | { | |
129 | return service_.get_io_context(); | |
130 | } | |
131 | ||
132 | /// (Deprecated: Use context().) Get the io_context associated with the | |
133 | /// strand. | |
7c673cae | 134 | /** |
b32b8144 | 135 | * This function may be used to obtain the io_context object that the strand |
7c673cae FG |
136 | * uses to dispatch handlers for asynchronous operations. |
137 | * | |
b32b8144 | 138 | * @return A reference to the io_context object that the strand will use to |
7c673cae FG |
139 | * dispatch handlers. Ownership is not transferred to the caller. |
140 | */ | |
b32b8144 FG |
141 | boost::asio::io_context& get_io_service() |
142 | { | |
143 | return service_.get_io_context(); | |
144 | } | |
145 | #endif // !defined(BOOST_ASIO_NO_DEPRECATED) | |
146 | ||
147 | /// Obtain the underlying execution context. | |
148 | boost::asio::io_context& context() const BOOST_ASIO_NOEXCEPT | |
149 | { | |
150 | return service_.get_io_context(); | |
151 | } | |
152 | ||
153 | /// Inform the strand that it has some outstanding work to do. | |
154 | /** | |
155 | * The strand delegates this call to its underlying io_context. | |
156 | */ | |
157 | void on_work_started() const BOOST_ASIO_NOEXCEPT | |
158 | { | |
159 | context().get_executor().on_work_started(); | |
160 | } | |
161 | ||
162 | /// Inform the strand that some work is no longer outstanding. | |
163 | /** | |
164 | * The strand delegates this call to its underlying io_context. | |
165 | */ | |
166 | void on_work_finished() const BOOST_ASIO_NOEXCEPT | |
167 | { | |
168 | context().get_executor().on_work_finished(); | |
169 | } | |
170 | ||
171 | /// Request the strand to invoke the given function object. | |
172 | /** | |
173 | * This function is used to ask the strand to execute the given function | |
174 | * object on its underlying io_context. The function object will be executed | |
175 | * inside this function if the strand is not otherwise busy and if the | |
176 | * underlying io_context's executor's @c dispatch() function is also able to | |
177 | * execute the function before returning. | |
178 | * | |
179 | * @param f The function object to be called. The executor will make | |
180 | * a copy of the handler object as required. The function signature of the | |
181 | * function object must be: @code void function(); @endcode | |
182 | * | |
183 | * @param a An allocator that may be used by the executor to allocate the | |
184 | * internal storage needed for function invocation. | |
185 | */ | |
186 | template <typename Function, typename Allocator> | |
187 | void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const | |
7c673cae | 188 | { |
b32b8144 FG |
189 | typename decay<Function>::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); |
190 | service_.dispatch(impl_, tmp); | |
191 | (void)a; | |
7c673cae FG |
192 | } |
193 | ||
b32b8144 FG |
194 | #if !defined(BOOST_ASIO_NO_DEPRECATED) |
195 | /// (Deprecated: Use boost::asio::dispatch().) Request the strand to invoke | |
196 | /// the given handler. | |
7c673cae FG |
197 | /** |
198 | * This function is used to ask the strand to execute the given handler. | |
199 | * | |
200 | * The strand object guarantees that handlers posted or dispatched through | |
201 | * the strand will not be executed concurrently. The handler may be executed | |
202 | * inside this function if the guarantee can be met. If this function is | |
203 | * called from within a handler that was posted or dispatched through the same | |
204 | * strand, then the new handler will be executed immediately. | |
205 | * | |
206 | * The strand's guarantee is in addition to the guarantee provided by the | |
b32b8144 FG |
207 | * underlying io_context. The io_context guarantees that the handler will only |
208 | * be called in a thread in which the io_context's run member function is | |
7c673cae FG |
209 | * currently being invoked. |
210 | * | |
211 | * @param handler The handler to be called. The strand will make a copy of the | |
212 | * handler object as required. The function signature of the handler must be: | |
213 | * @code void handler(); @endcode | |
214 | */ | |
11fdf7f2 TL |
215 | template <typename LegacyCompletionHandler> |
216 | BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) | |
217 | dispatch(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) | |
7c673cae FG |
218 | { |
219 | // If you get an error on the following line it means that your handler does | |
11fdf7f2 TL |
220 | // not meet the documented type requirements for a LegacyCompletionHandler. |
221 | BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( | |
222 | LegacyCompletionHandler, handler) type_check; | |
7c673cae | 223 | |
11fdf7f2 | 224 | async_completion<LegacyCompletionHandler, void ()> init(handler); |
7c673cae | 225 | |
b32b8144 | 226 | service_.dispatch(impl_, init.completion_handler); |
7c673cae FG |
227 | |
228 | return init.result.get(); | |
229 | } | |
b32b8144 FG |
230 | #endif // !defined(BOOST_ASIO_NO_DEPRECATED) |
231 | ||
232 | /// Request the strand to invoke the given function object. | |
233 | /** | |
234 | * This function is used to ask the executor to execute the given function | |
235 | * object. The function object will never be executed inside this function. | |
236 | * Instead, it will be scheduled to run by the underlying io_context. | |
237 | * | |
238 | * @param f The function object to be called. The executor will make | |
239 | * a copy of the handler object as required. The function signature of the | |
240 | * function object must be: @code void function(); @endcode | |
241 | * | |
242 | * @param a An allocator that may be used by the executor to allocate the | |
243 | * internal storage needed for function invocation. | |
244 | */ | |
245 | template <typename Function, typename Allocator> | |
246 | void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const | |
247 | { | |
248 | typename decay<Function>::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); | |
249 | service_.post(impl_, tmp); | |
250 | (void)a; | |
251 | } | |
7c673cae | 252 | |
b32b8144 FG |
253 | #if !defined(BOOST_ASIO_NO_DEPRECATED) |
254 | /// (Deprecated: Use boost::asio::post().) Request the strand to invoke the | |
255 | /// given handler and return immediately. | |
7c673cae FG |
256 | /** |
257 | * This function is used to ask the strand to execute the given handler, but | |
258 | * without allowing the strand to call the handler from inside this function. | |
259 | * | |
260 | * The strand object guarantees that handlers posted or dispatched through | |
261 | * the strand will not be executed concurrently. The strand's guarantee is in | |
b32b8144 FG |
262 | * addition to the guarantee provided by the underlying io_context. The |
263 | * io_context guarantees that the handler will only be called in a thread in | |
264 | * which the io_context's run member function is currently being invoked. | |
7c673cae FG |
265 | * |
266 | * @param handler The handler to be called. The strand will make a copy of the | |
267 | * handler object as required. The function signature of the handler must be: | |
268 | * @code void handler(); @endcode | |
269 | */ | |
11fdf7f2 TL |
270 | template <typename LegacyCompletionHandler> |
271 | BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) | |
272 | post(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) | |
7c673cae FG |
273 | { |
274 | // If you get an error on the following line it means that your handler does | |
11fdf7f2 TL |
275 | // not meet the documented type requirements for a LegacyCompletionHandler. |
276 | BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( | |
277 | LegacyCompletionHandler, handler) type_check; | |
7c673cae | 278 | |
11fdf7f2 | 279 | async_completion<LegacyCompletionHandler, void ()> init(handler); |
7c673cae | 280 | |
b32b8144 | 281 | service_.post(impl_, init.completion_handler); |
7c673cae FG |
282 | |
283 | return init.result.get(); | |
284 | } | |
b32b8144 FG |
285 | #endif // !defined(BOOST_ASIO_NO_DEPRECATED) |
286 | ||
287 | /// Request the strand to invoke the given function object. | |
288 | /** | |
289 | * This function is used to ask the executor to execute the given function | |
290 | * object. The function object will never be executed inside this function. | |
291 | * Instead, it will be scheduled to run by the underlying io_context. | |
292 | * | |
293 | * @param f The function object to be called. The executor will make | |
294 | * a copy of the handler object as required. The function signature of the | |
295 | * function object must be: @code void function(); @endcode | |
296 | * | |
297 | * @param a An allocator that may be used by the executor to allocate the | |
298 | * internal storage needed for function invocation. | |
299 | */ | |
300 | template <typename Function, typename Allocator> | |
301 | void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const | |
302 | { | |
303 | typename decay<Function>::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); | |
304 | service_.post(impl_, tmp); | |
305 | (void)a; | |
306 | } | |
7c673cae | 307 | |
b32b8144 FG |
308 | #if !defined(BOOST_ASIO_NO_DEPRECATED) |
309 | /// (Deprecated: Use boost::asio::bind_executor().) Create a new handler that | |
310 | /// automatically dispatches the wrapped handler on the strand. | |
7c673cae FG |
311 | /** |
312 | * This function is used to create a new handler function object that, when | |
313 | * invoked, will automatically pass the wrapped handler to the strand's | |
314 | * dispatch function. | |
315 | * | |
316 | * @param handler The handler to be wrapped. The strand will make a copy of | |
317 | * the handler object as required. The function signature of the handler must | |
318 | * be: @code void handler(A1 a1, ... An an); @endcode | |
319 | * | |
320 | * @return A function object that, when invoked, passes the wrapped handler to | |
321 | * the strand's dispatch function. Given a function object with the signature: | |
322 | * @code R f(A1 a1, ... An an); @endcode | |
323 | * If this function object is passed to the wrap function like so: | |
324 | * @code strand.wrap(f); @endcode | |
325 | * then the return value is a function object with the signature | |
326 | * @code void g(A1 a1, ... An an); @endcode | |
327 | * that, when invoked, executes code equivalent to: | |
328 | * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode | |
329 | */ | |
330 | template <typename Handler> | |
331 | #if defined(GENERATING_DOCUMENTATION) | |
332 | unspecified | |
333 | #else | |
334 | detail::wrapped_handler<strand, Handler, detail::is_continuation_if_running> | |
335 | #endif | |
336 | wrap(Handler handler) | |
337 | { | |
b32b8144 | 338 | return detail::wrapped_handler<io_context::strand, Handler, |
7c673cae FG |
339 | detail::is_continuation_if_running>(*this, handler); |
340 | } | |
b32b8144 | 341 | #endif // !defined(BOOST_ASIO_NO_DEPRECATED) |
7c673cae FG |
342 | |
343 | /// Determine whether the strand is running in the current thread. | |
344 | /** | |
345 | * @return @c true if the current thread is executing a handler that was | |
346 | * submitted to the strand using post(), dispatch() or wrap(). Otherwise | |
347 | * returns @c false. | |
348 | */ | |
b32b8144 | 349 | bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT |
7c673cae FG |
350 | { |
351 | return service_.running_in_this_thread(impl_); | |
352 | } | |
353 | ||
b32b8144 FG |
354 | /// Compare two strands for equality. |
355 | /** | |
356 | * Two strands are equal if they refer to the same ordered, non-concurrent | |
357 | * state. | |
358 | */ | |
359 | friend bool operator==(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT | |
360 | { | |
361 | return a.impl_ == b.impl_; | |
362 | } | |
363 | ||
364 | /// Compare two strands for inequality. | |
365 | /** | |
366 | * Two strands are equal if they refer to the same ordered, non-concurrent | |
367 | * state. | |
368 | */ | |
369 | friend bool operator!=(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT | |
370 | { | |
371 | return a.impl_ != b.impl_; | |
372 | } | |
373 | ||
7c673cae FG |
374 | private: |
375 | boost::asio::detail::strand_service& service_; | |
b32b8144 | 376 | mutable boost::asio::detail::strand_service::implementation_type impl_; |
7c673cae FG |
377 | }; |
378 | ||
7c673cae FG |
379 | } // namespace asio |
380 | } // namespace boost | |
381 | ||
382 | #include <boost/asio/detail/pop_options.hpp> | |
383 | ||
b32b8144 FG |
384 | #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) |
385 | ||
386 | #endif // BOOST_ASIO_IO_CONTEXT_STRAND_HPP |