5 // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #ifndef BOOST_ASIO_STRAND_HPP
12 #define BOOST_ASIO_STRAND_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/config.hpp>
19 #include <boost/asio/detail/strand_executor_service.hpp>
20 #include <boost/asio/detail/type_traits.hpp>
21 #include <boost/asio/execution/executor.hpp>
22 #include <boost/asio/is_executor.hpp>
24 #include <boost/asio/detail/push_options.hpp>
29 /// Provides serialised function invocation for any executor type.
30 template <typename Executor>
34 /// The type of the underlying executor.
35 typedef Executor inner_executor_type;
37 /// Default constructor.
39 * This constructor is only valid if the underlying executor type is default
44 impl_(strand::create_implementation(executor_))
48 /// Construct a strand for the specified executor.
49 template <typename Executor1>
50 explicit strand(const Executor1& e,
53 !is_same<Executor1, strand>::value,
54 is_convertible<Executor1, Executor>,
59 impl_(strand::create_implementation(executor_))
64 strand(const strand& other) BOOST_ASIO_NOEXCEPT
65 : executor_(other.executor_),
70 /// Converting constructor.
72 * This constructor is only valid if the @c OtherExecutor type is convertible
75 template <class OtherExecutor>
77 const strand<OtherExecutor>& other) BOOST_ASIO_NOEXCEPT
78 : executor_(other.executor_),
83 /// Assignment operator.
84 strand& operator=(const strand& other) BOOST_ASIO_NOEXCEPT
86 executor_ = other.executor_;
91 /// Converting assignment operator.
93 * This assignment operator is only valid if the @c OtherExecutor type is
94 * convertible to @c Executor.
96 template <class OtherExecutor>
98 const strand<OtherExecutor>& other) BOOST_ASIO_NOEXCEPT
100 executor_ = other.executor_;
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_))
113 /// Converting move constructor.
115 * This constructor is only valid if the @c OtherExecutor type is convertible
118 template <class OtherExecutor>
119 strand(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT
120 : executor_(BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.executor_)),
121 impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_))
125 /// Move assignment operator.
126 strand& operator=(strand&& other) BOOST_ASIO_NOEXCEPT
128 executor_ = BOOST_ASIO_MOVE_CAST(Executor)(other.executor_);
129 impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_);
133 /// Converting move assignment operator.
135 * This assignment operator is only valid if the @c OtherExecutor type is
136 * convertible to @c Executor.
138 template <class OtherExecutor>
139 strand& operator=(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT
141 executor_ = BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.executor_);
142 impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_);
145 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
148 ~strand() BOOST_ASIO_NOEXCEPT
152 /// Obtain the underlying executor.
153 inner_executor_type get_inner_executor() const BOOST_ASIO_NOEXCEPT
158 /// Forward a query to the underlying executor.
160 * Do not call this function directly. It is intended for use with the
161 * execution::execute customisation point.
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)
169 template <typename Property>
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))
177 return boost::asio::query(executor_, p);
180 /// Forward a requirement to the underlying executor.
182 * Do not call this function directly. It is intended for use with the
183 * boost::asio::require customisation point.
186 * @code boost::asio::strand<my_executor_type> ex1 = ...;
187 * auto ex2 = boost::asio::require(ex1,
188 * boost::asio::execution::blocking.never); @endcode
190 template <typename Property>
192 can_require<const Executor&, Property>::value,
193 strand<typename decay<
194 typename require_result<const Executor&, Property>::type
196 >::type require(const Property& p) const
197 BOOST_ASIO_NOEXCEPT_IF((
198 is_nothrow_require<const Executor&, Property>::value))
200 return strand<typename decay<
201 typename require_result<const Executor&, Property>::type
202 >::type>(boost::asio::require(executor_, p), impl_);
205 /// Forward a preference to the underlying executor.
207 * Do not call this function directly. It is intended for use with the
208 * boost::asio::prefer customisation point.
211 * @code boost::asio::strand<my_executor_type> ex1 = ...;
212 * auto ex2 = boost::asio::prefer(ex1,
213 * boost::asio::execution::blocking.never); @endcode
215 template <typename Property>
217 can_prefer<const Executor&, Property>::value,
218 strand<typename decay<
219 typename prefer_result<const Executor&, Property>::type
221 >::type prefer(const Property& p) const
222 BOOST_ASIO_NOEXCEPT_IF((
223 is_nothrow_prefer<const Executor&, Property>::value))
225 return strand<typename decay<
226 typename prefer_result<const Executor&, Property>::type
227 >::type>(boost::asio::prefer(executor_, p), impl_);
230 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
231 /// Obtain the underlying execution context.
232 execution_context& context() const BOOST_ASIO_NOEXCEPT
234 return executor_.context();
237 /// Inform the strand that it has some outstanding work to do.
239 * The strand delegates this call to its underlying executor.
241 void on_work_started() const BOOST_ASIO_NOEXCEPT
243 executor_.on_work_started();
246 /// Inform the strand that some work is no longer outstanding.
248 * The strand delegates this call to its underlying executor.
250 void on_work_finished() const BOOST_ASIO_NOEXCEPT
252 executor_.on_work_finished();
254 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
256 /// Request the strand to invoke the given function object.
258 * Do not call this function directly. It is intended for use with the
259 * execution::execute customisation point.
262 * @code boost::asio::strand<my_executor_type> ex = ...;
263 * execution::execute(ex, my_function_object); @endcode
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.
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
273 template <typename Function>
275 execution::can_execute<const Executor&, Function>::value
276 >::type execute(BOOST_ASIO_MOVE_ARG(Function) f) const
278 detail::strand_executor_service::execute(impl_,
279 executor_, BOOST_ASIO_MOVE_CAST(Function)(f));
282 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
283 /// Request the strand to invoke the given function object.
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.
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
295 * @param a An allocator that may be used by the executor to allocate the
296 * internal storage needed for function invocation.
298 template <typename Function, typename Allocator>
299 void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
301 detail::strand_executor_service::dispatch(impl_,
302 executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
305 /// Request the strand to invoke the given function object.
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.
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
315 * @param a An allocator that may be used by the executor to allocate the
316 * internal storage needed for function invocation.
318 template <typename Function, typename Allocator>
319 void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
321 detail::strand_executor_service::post(impl_,
322 executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
325 /// Request the strand to invoke the given function object.
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.
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
335 * @param a An allocator that may be used by the executor to allocate the
336 * internal storage needed for function invocation.
338 template <typename Function, typename Allocator>
339 void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
341 detail::strand_executor_service::defer(impl_,
342 executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
344 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
346 /// Determine whether the strand is running in the current thread.
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
352 bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT
354 return detail::strand_executor_service::running_in_this_thread(impl_);
357 /// Compare two strands for equality.
359 * Two strands are equal if they refer to the same ordered, non-concurrent
362 friend bool operator==(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT
364 return a.impl_ == b.impl_;
367 /// Compare two strands for inequality.
369 * Two strands are equal if they refer to the same ordered, non-concurrent
372 friend bool operator!=(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT
374 return a.impl_ != b.impl_;
377 #if defined(GENERATING_DOCUMENTATION)
379 #endif // defined(GENERATING_DOCUMENTATION)
380 typedef detail::strand_executor_service::implementation_type
383 template <typename InnerExecutor>
384 static implementation_type create_implementation(const InnerExecutor& ex,
386 can_query<InnerExecutor, execution::context_t>::value
389 return use_service<detail::strand_executor_service>(
390 boost::asio::query(ex, execution::context)).create_implementation();
393 template <typename InnerExecutor>
394 static implementation_type create_implementation(const InnerExecutor& ex,
396 !can_query<InnerExecutor, execution::context_t>::value
399 return use_service<detail::strand_executor_service>(
400 ex.context()).create_implementation();
403 strand(const Executor& ex, const implementation_type& impl)
410 implementation_type impl_;
413 /** @defgroup make_strand boost::asio::make_strand
415 * @brief The boost::asio::make_strand function creates a @ref strand object for
416 * an executor or execution context.
420 /// Create a @ref strand object for an executor.
421 template <typename Executor>
422 inline strand<Executor> make_strand(const Executor& ex,
424 is_executor<Executor>::value || execution::is_executor<Executor>::value
427 return strand<Executor>(ex);
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,
435 is_convertible<ExecutionContext&, execution_context&>::value
438 return strand<typename ExecutionContext::executor_type>(ctx.get_executor());
443 #if !defined(GENERATING_DOCUMENTATION)
447 #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
449 template <typename Executor>
450 struct equality_comparable<strand<Executor> >
452 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
453 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
456 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
458 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
460 template <typename Executor, typename Function>
461 struct execute_member<strand<Executor>, Function,
463 execution::can_execute<const Executor&, Function>::value
466 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
467 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
468 typedef void result_type;
471 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
473 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
475 template <typename Executor, typename Property>
476 struct query_member<strand<Executor>, Property,
478 can_query<const Executor&, Property>::value
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;
487 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
489 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
491 template <typename Executor, typename Property>
492 struct require_member<strand<Executor>, Property,
494 can_require<const Executor&, Property>::value
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;
505 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
507 #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
509 template <typename Executor, typename Property>
510 struct prefer_member<strand<Executor>, Property,
512 can_prefer<const Executor&, Property>::value
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;
523 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
525 } // namespace traits
527 #endif // !defined(GENERATING_DOCUMENTATION)
532 #include <boost/asio/detail/pop_options.hpp>
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)
542 #endif // BOOST_ASIO_STRAND_HPP