]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // strand.hpp | |
3 | // ~~~~~~~~~~ | |
4 | // | |
f67539c2 | 5 | // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
b32b8144 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 | ||
11 | #ifndef BOOST_ASIO_STRAND_HPP | |
12 | #define BOOST_ASIO_STRAND_HPP | |
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> | |
19 | #include <boost/asio/detail/strand_executor_service.hpp> | |
20 | #include <boost/asio/detail/type_traits.hpp> | |
20effc67 TL |
21 | #include <boost/asio/execution/executor.hpp> |
22 | #include <boost/asio/is_executor.hpp> | |
b32b8144 FG |
23 | |
24 | #include <boost/asio/detail/push_options.hpp> | |
25 | ||
26 | namespace boost { | |
27 | namespace asio { | |
28 | ||
29 | /// Provides serialised function invocation for any executor type. | |
30 | template <typename Executor> | |
31 | class strand | |
32 | { | |
33 | public: | |
34 | /// The type of the underlying executor. | |
35 | typedef Executor inner_executor_type; | |
36 | ||
37 | /// Default constructor. | |
38 | /** | |
39 | * This constructor is only valid if the underlying executor type is default | |
40 | * constructible. | |
41 | */ | |
42 | strand() | |
43 | : executor_(), | |
20effc67 | 44 | impl_(strand::create_implementation(executor_)) |
b32b8144 FG |
45 | { |
46 | } | |
47 | ||
48 | /// Construct a strand for the specified executor. | |
20effc67 TL |
49 | template <typename Executor1> |
50 | explicit strand(const Executor1& e, | |
51 | typename enable_if< | |
52 | conditional< | |
53 | !is_same<Executor1, strand>::value, | |
54 | is_convertible<Executor1, Executor>, | |
55 | false_type | |
56 | >::type::value | |
57 | >::type* = 0) | |
b32b8144 | 58 | : executor_(e), |
20effc67 | 59 | impl_(strand::create_implementation(executor_)) |
b32b8144 FG |
60 | { |
61 | } | |
62 | ||
63 | /// Copy constructor. | |
64 | strand(const strand& other) BOOST_ASIO_NOEXCEPT | |
65 | : executor_(other.executor_), | |
66 | impl_(other.impl_) | |
67 | { | |
68 | } | |
69 | ||
70 | /// Converting constructor. | |
71 | /** | |
72 | * This constructor is only valid if the @c OtherExecutor type is convertible | |
73 | * to @c Executor. | |
74 | */ | |
75 | template <class OtherExecutor> | |
76 | strand( | |
77 | const strand<OtherExecutor>& other) BOOST_ASIO_NOEXCEPT | |
78 | : executor_(other.executor_), | |
79 | impl_(other.impl_) | |
80 | { | |
81 | } | |
82 | ||
83 | /// Assignment operator. | |
84 | strand& operator=(const strand& other) BOOST_ASIO_NOEXCEPT | |
85 | { | |
86 | executor_ = other.executor_; | |
87 | impl_ = other.impl_; | |
88 | return *this; | |
89 | } | |
90 | ||
91 | /// Converting assignment operator. | |
92 | /** | |
93 | * This assignment operator is only valid if the @c OtherExecutor type is | |
94 | * convertible to @c Executor. | |
95 | */ | |
96 | template <class OtherExecutor> | |
97 | strand& operator=( | |
98 | const strand<OtherExecutor>& other) BOOST_ASIO_NOEXCEPT | |
99 | { | |
100 | executor_ = other.executor_; | |
101 | impl_ = other.impl_; | |
102 | return *this; | |
103 | } | |
104 | ||
105 | #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) | |
106 | /// Move constructor. | |
107 | strand(strand&& other) BOOST_ASIO_NOEXCEPT | |
108 | : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), | |
109 | impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)) | |
110 | { | |
111 | } | |
112 | ||
113 | /// Converting move constructor. | |
114 | /** | |
115 | * This constructor is only valid if the @c OtherExecutor type is convertible | |
116 | * to @c Executor. | |
117 | */ | |
118 | template <class OtherExecutor> | |
119 | strand(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT | |
f67539c2 | 120 | : executor_(BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.executor_)), |
b32b8144 FG |
121 | impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)) |
122 | { | |
123 | } | |
124 | ||
125 | /// Move assignment operator. | |
126 | strand& operator=(strand&& other) BOOST_ASIO_NOEXCEPT | |
127 | { | |
f67539c2 | 128 | executor_ = BOOST_ASIO_MOVE_CAST(Executor)(other.executor_); |
b32b8144 FG |
129 | impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_); |
130 | return *this; | |
131 | } | |
132 | ||
133 | /// Converting move assignment operator. | |
134 | /** | |
135 | * This assignment operator is only valid if the @c OtherExecutor type is | |
136 | * convertible to @c Executor. | |
137 | */ | |
138 | template <class OtherExecutor> | |
f67539c2 | 139 | strand& operator=(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT |
b32b8144 | 140 | { |
f67539c2 | 141 | executor_ = BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.executor_); |
b32b8144 FG |
142 | impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_); |
143 | return *this; | |
144 | } | |
145 | #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) | |
146 | ||
147 | /// Destructor. | |
20effc67 | 148 | ~strand() BOOST_ASIO_NOEXCEPT |
b32b8144 FG |
149 | { |
150 | } | |
151 | ||
152 | /// Obtain the underlying executor. | |
153 | inner_executor_type get_inner_executor() const BOOST_ASIO_NOEXCEPT | |
154 | { | |
155 | return executor_; | |
156 | } | |
157 | ||
20effc67 TL |
158 | /// Forward a query to the underlying executor. |
159 | /** | |
160 | * Do not call this function directly. It is intended for use with the | |
161 | * execution::execute customisation point. | |
162 | * | |
163 | * For example: | |
164 | * @code boost::asio::strand<my_executor_type> ex = ...; | |
165 | * if (boost::asio::query(ex, boost::asio::execution::blocking) | |
166 | * == boost::asio::execution::blocking.never) | |
167 | * ... @endcode | |
168 | */ | |
169 | template <typename Property> | |
170 | typename enable_if< | |
171 | can_query<const Executor&, Property>::value, | |
172 | typename query_result<const Executor&, Property>::type | |
173 | >::type query(const Property& p) const | |
174 | BOOST_ASIO_NOEXCEPT_IF(( | |
175 | is_nothrow_query<const Executor&, Property>::value)) | |
176 | { | |
177 | return boost::asio::query(executor_, p); | |
178 | } | |
179 | ||
180 | /// Forward a requirement to the underlying executor. | |
181 | /** | |
182 | * Do not call this function directly. It is intended for use with the | |
183 | * boost::asio::require customisation point. | |
184 | * | |
185 | * For example: | |
186 | * @code boost::asio::strand<my_executor_type> ex1 = ...; | |
187 | * auto ex2 = boost::asio::require(ex1, | |
188 | * boost::asio::execution::blocking.never); @endcode | |
189 | */ | |
190 | template <typename Property> | |
191 | typename enable_if< | |
192 | can_require<const Executor&, Property>::value, | |
193 | strand<typename decay< | |
194 | typename require_result<const Executor&, Property>::type | |
195 | >::type> | |
196 | >::type require(const Property& p) const | |
197 | BOOST_ASIO_NOEXCEPT_IF(( | |
198 | is_nothrow_require<const Executor&, Property>::value)) | |
199 | { | |
200 | return strand<typename decay< | |
201 | typename require_result<const Executor&, Property>::type | |
202 | >::type>(boost::asio::require(executor_, p), impl_); | |
203 | } | |
204 | ||
205 | /// Forward a preference to the underlying executor. | |
206 | /** | |
207 | * Do not call this function directly. It is intended for use with the | |
208 | * boost::asio::prefer customisation point. | |
209 | * | |
210 | * For example: | |
211 | * @code boost::asio::strand<my_executor_type> ex1 = ...; | |
212 | * auto ex2 = boost::asio::prefer(ex1, | |
213 | * boost::asio::execution::blocking.never); @endcode | |
214 | */ | |
215 | template <typename Property> | |
216 | typename enable_if< | |
217 | can_prefer<const Executor&, Property>::value, | |
218 | strand<typename decay< | |
219 | typename prefer_result<const Executor&, Property>::type | |
220 | >::type> | |
221 | >::type prefer(const Property& p) const | |
222 | BOOST_ASIO_NOEXCEPT_IF(( | |
223 | is_nothrow_prefer<const Executor&, Property>::value)) | |
224 | { | |
225 | return strand<typename decay< | |
226 | typename prefer_result<const Executor&, Property>::type | |
227 | >::type>(boost::asio::prefer(executor_, p), impl_); | |
228 | } | |
229 | ||
230 | #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) | |
b32b8144 FG |
231 | /// Obtain the underlying execution context. |
232 | execution_context& context() const BOOST_ASIO_NOEXCEPT | |
233 | { | |
234 | return executor_.context(); | |
235 | } | |
236 | ||
237 | /// Inform the strand that it has some outstanding work to do. | |
238 | /** | |
239 | * The strand delegates this call to its underlying executor. | |
240 | */ | |
241 | void on_work_started() const BOOST_ASIO_NOEXCEPT | |
242 | { | |
243 | executor_.on_work_started(); | |
244 | } | |
245 | ||
246 | /// Inform the strand that some work is no longer outstanding. | |
247 | /** | |
248 | * The strand delegates this call to its underlying executor. | |
249 | */ | |
250 | void on_work_finished() const BOOST_ASIO_NOEXCEPT | |
251 | { | |
252 | executor_.on_work_finished(); | |
253 | } | |
20effc67 TL |
254 | #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) |
255 | ||
256 | /// Request the strand to invoke the given function object. | |
257 | /** | |
258 | * Do not call this function directly. It is intended for use with the | |
259 | * execution::execute customisation point. | |
260 | * | |
261 | * For example: | |
262 | * @code boost::asio::strand<my_executor_type> ex = ...; | |
263 | * execution::execute(ex, my_function_object); @endcode | |
264 | * | |
265 | * This function is used to ask the strand to execute the given function | |
266 | * object on its underlying executor. The function object will be executed | |
267 | * according to the properties of the underlying executor. | |
268 | * | |
269 | * @param f The function object to be called. The executor will make | |
270 | * a copy of the handler object as required. The function signature of the | |
271 | * function object must be: @code void function(); @endcode | |
272 | */ | |
273 | template <typename Function> | |
274 | typename enable_if< | |
275 | execution::can_execute<const Executor&, Function>::value | |
276 | >::type execute(BOOST_ASIO_MOVE_ARG(Function) f) const | |
277 | { | |
278 | detail::strand_executor_service::execute(impl_, | |
279 | executor_, BOOST_ASIO_MOVE_CAST(Function)(f)); | |
280 | } | |
b32b8144 | 281 | |
20effc67 | 282 | #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) |
b32b8144 FG |
283 | /// Request the strand to invoke the given function object. |
284 | /** | |
285 | * This function is used to ask the strand to execute the given function | |
286 | * object on its underlying executor. The function object will be executed | |
287 | * inside this function if the strand is not otherwise busy and if the | |
288 | * underlying executor's @c dispatch() function is also able to execute the | |
289 | * function before returning. | |
290 | * | |
291 | * @param f The function object to be called. The executor will make | |
292 | * a copy of the handler object as required. The function signature of the | |
293 | * function object must be: @code void function(); @endcode | |
294 | * | |
295 | * @param a An allocator that may be used by the executor to allocate the | |
296 | * internal storage needed for function invocation. | |
297 | */ | |
298 | template <typename Function, typename Allocator> | |
299 | void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const | |
300 | { | |
301 | detail::strand_executor_service::dispatch(impl_, | |
302 | executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a); | |
303 | } | |
304 | ||
305 | /// Request the strand to invoke the given function object. | |
306 | /** | |
307 | * This function is used to ask the executor to execute the given function | |
308 | * object. The function object will never be executed inside this function. | |
309 | * Instead, it will be scheduled by the underlying executor's defer function. | |
310 | * | |
311 | * @param f The function object to be called. The executor will make | |
312 | * a copy of the handler object as required. The function signature of the | |
313 | * function object must be: @code void function(); @endcode | |
314 | * | |
315 | * @param a An allocator that may be used by the executor to allocate the | |
316 | * internal storage needed for function invocation. | |
317 | */ | |
318 | template <typename Function, typename Allocator> | |
319 | void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const | |
320 | { | |
321 | detail::strand_executor_service::post(impl_, | |
322 | executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a); | |
323 | } | |
324 | ||
325 | /// Request the strand to invoke the given function object. | |
326 | /** | |
327 | * This function is used to ask the executor to execute the given function | |
328 | * object. The function object will never be executed inside this function. | |
329 | * Instead, it will be scheduled by the underlying executor's defer function. | |
330 | * | |
331 | * @param f The function object to be called. The executor will make | |
332 | * a copy of the handler object as required. The function signature of the | |
333 | * function object must be: @code void function(); @endcode | |
334 | * | |
335 | * @param a An allocator that may be used by the executor to allocate the | |
336 | * internal storage needed for function invocation. | |
337 | */ | |
338 | template <typename Function, typename Allocator> | |
339 | void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const | |
340 | { | |
341 | detail::strand_executor_service::defer(impl_, | |
342 | executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a); | |
343 | } | |
20effc67 | 344 | #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) |
b32b8144 FG |
345 | |
346 | /// Determine whether the strand is running in the current thread. | |
347 | /** | |
348 | * @return @c true if the current thread is executing a function that was | |
349 | * submitted to the strand using post(), dispatch() or defer(). Otherwise | |
350 | * returns @c false. | |
351 | */ | |
352 | bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT | |
353 | { | |
354 | return detail::strand_executor_service::running_in_this_thread(impl_); | |
355 | } | |
356 | ||
357 | /// Compare two strands for equality. | |
358 | /** | |
359 | * Two strands are equal if they refer to the same ordered, non-concurrent | |
360 | * state. | |
361 | */ | |
362 | friend bool operator==(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT | |
363 | { | |
364 | return a.impl_ == b.impl_; | |
365 | } | |
366 | ||
367 | /// Compare two strands for inequality. | |
368 | /** | |
369 | * Two strands are equal if they refer to the same ordered, non-concurrent | |
370 | * state. | |
371 | */ | |
372 | friend bool operator!=(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT | |
373 | { | |
374 | return a.impl_ != b.impl_; | |
375 | } | |
376 | ||
f67539c2 | 377 | #if defined(GENERATING_DOCUMENTATION) |
b32b8144 | 378 | private: |
f67539c2 | 379 | #endif // defined(GENERATING_DOCUMENTATION) |
b32b8144 FG |
380 | typedef detail::strand_executor_service::implementation_type |
381 | implementation_type; | |
20effc67 TL |
382 | |
383 | template <typename InnerExecutor> | |
384 | static implementation_type create_implementation(const InnerExecutor& ex, | |
385 | typename enable_if< | |
386 | can_query<InnerExecutor, execution::context_t>::value | |
387 | >::type* = 0) | |
388 | { | |
389 | return use_service<detail::strand_executor_service>( | |
390 | boost::asio::query(ex, execution::context)).create_implementation(); | |
391 | } | |
392 | ||
393 | template <typename InnerExecutor> | |
394 | static implementation_type create_implementation(const InnerExecutor& ex, | |
395 | typename enable_if< | |
396 | !can_query<InnerExecutor, execution::context_t>::value | |
397 | >::type* = 0) | |
398 | { | |
399 | return use_service<detail::strand_executor_service>( | |
400 | ex.context()).create_implementation(); | |
401 | } | |
402 | ||
403 | strand(const Executor& ex, const implementation_type& impl) | |
404 | : executor_(ex), | |
405 | impl_(impl) | |
406 | { | |
407 | } | |
408 | ||
409 | Executor executor_; | |
b32b8144 FG |
410 | implementation_type impl_; |
411 | }; | |
412 | ||
92f5a8d4 TL |
413 | /** @defgroup make_strand boost::asio::make_strand |
414 | * | |
415 | * @brief The boost::asio::make_strand function creates a @ref strand object for | |
416 | * an executor or execution context. | |
417 | */ | |
418 | /*@{*/ | |
419 | ||
420 | /// Create a @ref strand object for an executor. | |
421 | template <typename Executor> | |
422 | inline strand<Executor> make_strand(const Executor& ex, | |
20effc67 TL |
423 | typename enable_if< |
424 | is_executor<Executor>::value || execution::is_executor<Executor>::value | |
425 | >::type* = 0) | |
92f5a8d4 TL |
426 | { |
427 | return strand<Executor>(ex); | |
428 | } | |
429 | ||
430 | /// Create a @ref strand object for an execution context. | |
431 | template <typename ExecutionContext> | |
432 | inline strand<typename ExecutionContext::executor_type> | |
433 | make_strand(ExecutionContext& ctx, | |
434 | typename enable_if< | |
20effc67 TL |
435 | is_convertible<ExecutionContext&, execution_context&>::value |
436 | >::type* = 0) | |
92f5a8d4 TL |
437 | { |
438 | return strand<typename ExecutionContext::executor_type>(ctx.get_executor()); | |
439 | } | |
440 | ||
441 | /*@}*/ | |
442 | ||
20effc67 TL |
443 | #if !defined(GENERATING_DOCUMENTATION) |
444 | ||
445 | namespace traits { | |
446 | ||
447 | #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) | |
448 | ||
449 | template <typename Executor> | |
450 | struct equality_comparable<strand<Executor> > | |
451 | { | |
452 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); | |
453 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); | |
454 | }; | |
455 | ||
456 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) | |
457 | ||
458 | #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) | |
459 | ||
460 | template <typename Executor, typename Function> | |
461 | struct execute_member<strand<Executor>, Function, | |
462 | typename enable_if< | |
463 | execution::can_execute<const Executor&, Function>::value | |
464 | >::type> | |
465 | { | |
466 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); | |
467 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); | |
468 | typedef void result_type; | |
469 | }; | |
470 | ||
471 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) | |
472 | ||
473 | #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) | |
474 | ||
475 | template <typename Executor, typename Property> | |
476 | struct query_member<strand<Executor>, Property, | |
477 | typename enable_if< | |
478 | can_query<const Executor&, Property>::value | |
479 | >::type> | |
480 | { | |
481 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); | |
482 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = | |
483 | (is_nothrow_query<Executor, Property>::value)); | |
484 | typedef typename query_result<Executor, Property>::type result_type; | |
485 | }; | |
486 | ||
487 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) | |
488 | ||
489 | #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) | |
490 | ||
491 | template <typename Executor, typename Property> | |
492 | struct require_member<strand<Executor>, Property, | |
493 | typename enable_if< | |
494 | can_require<const Executor&, Property>::value | |
495 | >::type> | |
496 | { | |
497 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); | |
498 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = | |
499 | (is_nothrow_require<Executor, Property>::value)); | |
500 | typedef strand<typename decay< | |
501 | typename require_result<Executor, Property>::type | |
502 | >::type> result_type; | |
503 | }; | |
504 | ||
505 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) | |
506 | ||
507 | #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) | |
508 | ||
509 | template <typename Executor, typename Property> | |
510 | struct prefer_member<strand<Executor>, Property, | |
511 | typename enable_if< | |
512 | can_prefer<const Executor&, Property>::value | |
513 | >::type> | |
514 | { | |
515 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); | |
516 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = | |
517 | (is_nothrow_prefer<Executor, Property>::value)); | |
518 | typedef strand<typename decay< | |
519 | typename prefer_result<Executor, Property>::type | |
520 | >::type> result_type; | |
521 | }; | |
522 | ||
523 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) | |
524 | ||
525 | } // namespace traits | |
526 | ||
527 | #endif // !defined(GENERATING_DOCUMENTATION) | |
528 | ||
b32b8144 FG |
529 | } // namespace asio |
530 | } // namespace boost | |
531 | ||
532 | #include <boost/asio/detail/pop_options.hpp> | |
533 | ||
534 | // If both io_context.hpp and strand.hpp have been included, automatically | |
535 | // include the header file needed for the io_context::strand class. | |
536 | #if !defined(BOOST_ASIO_NO_EXTENSIONS) | |
537 | # if defined(BOOST_ASIO_IO_CONTEXT_HPP) | |
538 | # include <boost/asio/io_context_strand.hpp> | |
539 | # endif // defined(BOOST_ASIO_IO_CONTEXT_HPP) | |
540 | #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) | |
541 | ||
542 | #endif // BOOST_ASIO_STRAND_HPP |