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

source code of boost/libs/asio/include/boost/asio/strand.hpp