![]() |
|
|||
File indexing completed on 2025-09-17 08:23:49
0001 // 0002 // io_context_strand.hpp 0003 // ~~~~~~~~~~~~~~~~~~~~~ 0004 // 0005 // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com) 0006 // 0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying 0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 0009 // 0010 0011 #ifndef BOOST_ASIO_IO_CONTEXT_STRAND_HPP 0012 #define BOOST_ASIO_IO_CONTEXT_STRAND_HPP 0013 0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 0015 # pragma once 0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 0017 0018 #include <boost/asio/detail/config.hpp> 0019 0020 #if !defined(BOOST_ASIO_NO_EXTENSIONS) \ 0021 && !defined(BOOST_ASIO_NO_TS_EXECUTORS) 0022 0023 #include <boost/asio/async_result.hpp> 0024 #include <boost/asio/detail/handler_type_requirements.hpp> 0025 #include <boost/asio/detail/strand_service.hpp> 0026 #include <boost/asio/detail/wrapped_handler.hpp> 0027 #include <boost/asio/io_context.hpp> 0028 0029 #include <boost/asio/detail/push_options.hpp> 0030 0031 namespace boost { 0032 namespace asio { 0033 0034 /// Provides serialised handler execution. 0035 /** 0036 * The io_context::strand class provides the ability to post and dispatch 0037 * handlers with the guarantee that none of those handlers will execute 0038 * concurrently. 0039 * 0040 * @par Order of handler invocation 0041 * Given: 0042 * 0043 * @li a strand object @c s 0044 * 0045 * @li an object @c a meeting completion handler requirements 0046 * 0047 * @li an object @c a1 which is an arbitrary copy of @c a made by the 0048 * implementation 0049 * 0050 * @li an object @c b meeting completion handler requirements 0051 * 0052 * @li an object @c b1 which is an arbitrary copy of @c b made by the 0053 * implementation 0054 * 0055 * if any of the following conditions are true: 0056 * 0057 * @li @c s.post(a) happens-before @c s.post(b) 0058 * 0059 * @li @c s.post(a) happens-before @c s.dispatch(b), where the latter is 0060 * performed outside the strand 0061 * 0062 * @li @c s.dispatch(a) happens-before @c s.post(b), where the former is 0063 * performed outside the strand 0064 * 0065 * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are 0066 * performed outside the strand 0067 * 0068 * then @c a() happens-before @c b() 0069 * 0070 * Note that in the following case: 0071 * @code async_op_1(..., s.wrap(a)); 0072 * async_op_2(..., s.wrap(b)); @endcode 0073 * the completion of the first async operation will perform @c s.dispatch(a), 0074 * and the second will perform @c s.dispatch(b), but the order in which those 0075 * are performed is unspecified. That is, you cannot state whether one 0076 * happens-before the other. Therefore none of the above conditions are met and 0077 * no ordering guarantee is made. 0078 * 0079 * @note The implementation makes no guarantee that handlers posted or 0080 * dispatched through different @c strand objects will be invoked concurrently. 0081 * 0082 * @par Thread Safety 0083 * @e Distinct @e objects: Safe.@n 0084 * @e Shared @e objects: Safe. 0085 * 0086 * @par Concepts: 0087 * Dispatcher. 0088 */ 0089 class io_context::strand 0090 { 0091 public: 0092 /// Constructor. 0093 /** 0094 * Constructs the strand. 0095 * 0096 * @param io_context The io_context object that the strand will use to 0097 * dispatch handlers that are ready to be run. 0098 */ 0099 explicit strand(boost::asio::io_context& io_context) 0100 : service_(boost::asio::use_service< 0101 boost::asio::detail::strand_service>(io_context)) 0102 { 0103 service_.construct(impl_); 0104 } 0105 0106 /// Copy constructor. 0107 /** 0108 * Creates a copy such that both strand objects share the same underlying 0109 * state. 0110 */ 0111 strand(const strand& other) noexcept 0112 : service_(other.service_), 0113 impl_(other.impl_) 0114 { 0115 } 0116 0117 /// Destructor. 0118 /** 0119 * Destroys a strand. 0120 * 0121 * Handlers posted through the strand that have not yet been invoked will 0122 * still be dispatched in a way that meets the guarantee of non-concurrency. 0123 */ 0124 ~strand() 0125 { 0126 } 0127 0128 /// Obtain the underlying execution context. 0129 boost::asio::io_context& context() const noexcept 0130 { 0131 return service_.get_io_context(); 0132 } 0133 0134 /// Inform the strand that it has some outstanding work to do. 0135 /** 0136 * The strand delegates this call to its underlying io_context. 0137 */ 0138 void on_work_started() const noexcept 0139 { 0140 context().get_executor().on_work_started(); 0141 } 0142 0143 /// Inform the strand that some work is no longer outstanding. 0144 /** 0145 * The strand delegates this call to its underlying io_context. 0146 */ 0147 void on_work_finished() const noexcept 0148 { 0149 context().get_executor().on_work_finished(); 0150 } 0151 0152 /// Request the strand to invoke the given function object. 0153 /** 0154 * This function is used to ask the strand to execute the given function 0155 * object on its underlying io_context. The function object will be executed 0156 * inside this function if the strand is not otherwise busy and if the 0157 * underlying io_context's executor's @c dispatch() function is also able to 0158 * execute the function before returning. 0159 * 0160 * @param f The function object to be called. The executor will make 0161 * a copy of the handler object as required. The function signature of the 0162 * function object must be: @code void function(); @endcode 0163 * 0164 * @param a An allocator that may be used by the executor to allocate the 0165 * internal storage needed for function invocation. 0166 */ 0167 template <typename Function, typename Allocator> 0168 void dispatch(Function&& f, const Allocator& a) const 0169 { 0170 decay_t<Function> tmp(static_cast<Function&&>(f)); 0171 service_.dispatch(impl_, tmp); 0172 (void)a; 0173 } 0174 0175 /// Request the strand to invoke the given function object. 0176 /** 0177 * This function is used to ask the executor to execute the given function 0178 * object. The function object will never be executed inside this function. 0179 * Instead, it will be scheduled to run by the underlying io_context. 0180 * 0181 * @param f The function object to be called. The executor will make 0182 * a copy of the handler object as required. The function signature of the 0183 * function object must be: @code void function(); @endcode 0184 * 0185 * @param a An allocator that may be used by the executor to allocate the 0186 * internal storage needed for function invocation. 0187 */ 0188 template <typename Function, typename Allocator> 0189 void post(Function&& f, const Allocator& a) const 0190 { 0191 decay_t<Function> tmp(static_cast<Function&&>(f)); 0192 service_.post(impl_, tmp); 0193 (void)a; 0194 } 0195 0196 /// Request the strand to invoke the given function object. 0197 /** 0198 * This function is used to ask the executor to execute the given function 0199 * object. The function object will never be executed inside this function. 0200 * Instead, it will be scheduled to run by the underlying io_context. 0201 * 0202 * @param f The function object to be called. The executor will make 0203 * a copy of the handler object as required. The function signature of the 0204 * function object must be: @code void function(); @endcode 0205 * 0206 * @param a An allocator that may be used by the executor to allocate the 0207 * internal storage needed for function invocation. 0208 */ 0209 template <typename Function, typename Allocator> 0210 void defer(Function&& f, const Allocator& a) const 0211 { 0212 decay_t<Function> tmp(static_cast<Function&&>(f)); 0213 service_.post(impl_, tmp); 0214 (void)a; 0215 } 0216 0217 #if !defined(BOOST_ASIO_NO_DEPRECATED) 0218 /// (Deprecated: Use boost::asio::bind_executor().) Create a new handler that 0219 /// automatically dispatches the wrapped handler on the strand. 0220 /** 0221 * This function is used to create a new handler function object that, when 0222 * invoked, will automatically pass the wrapped handler to the strand's 0223 * dispatch function. 0224 * 0225 * @param handler The handler to be wrapped. The strand will make a copy of 0226 * the handler object as required. The function signature of the handler must 0227 * be: @code void handler(A1 a1, ... An an); @endcode 0228 * 0229 * @return A function object that, when invoked, passes the wrapped handler to 0230 * the strand's dispatch function. Given a function object with the signature: 0231 * @code R f(A1 a1, ... An an); @endcode 0232 * If this function object is passed to the wrap function like so: 0233 * @code strand.wrap(f); @endcode 0234 * then the return value is a function object with the signature 0235 * @code void g(A1 a1, ... An an); @endcode 0236 * that, when invoked, executes code equivalent to: 0237 * @code boost::asio::dispatch(strand, boost::bind(f, a1, ... an)); @endcode 0238 */ 0239 template <typename Handler> 0240 #if defined(GENERATING_DOCUMENTATION) 0241 unspecified 0242 #else 0243 detail::wrapped_handler<strand, Handler, detail::is_continuation_if_running> 0244 #endif 0245 wrap(Handler handler) 0246 { 0247 return detail::wrapped_handler<io_context::strand, Handler, 0248 detail::is_continuation_if_running>(*this, handler); 0249 } 0250 #endif // !defined(BOOST_ASIO_NO_DEPRECATED) 0251 0252 /// Determine whether the strand is running in the current thread. 0253 /** 0254 * @return @c true if the current thread is executing a handler that was 0255 * submitted to the strand using post(), dispatch() or wrap(). Otherwise 0256 * returns @c false. 0257 */ 0258 bool running_in_this_thread() const noexcept 0259 { 0260 return service_.running_in_this_thread(impl_); 0261 } 0262 0263 /// Compare two strands for equality. 0264 /** 0265 * Two strands are equal if they refer to the same ordered, non-concurrent 0266 * state. 0267 */ 0268 friend bool operator==(const strand& a, const strand& b) noexcept 0269 { 0270 return a.impl_ == b.impl_; 0271 } 0272 0273 /// Compare two strands for inequality. 0274 /** 0275 * Two strands are equal if they refer to the same ordered, non-concurrent 0276 * state. 0277 */ 0278 friend bool operator!=(const strand& a, const strand& b) noexcept 0279 { 0280 return a.impl_ != b.impl_; 0281 } 0282 0283 private: 0284 boost::asio::detail::strand_service& service_; 0285 mutable boost::asio::detail::strand_service::implementation_type impl_; 0286 }; 0287 0288 } // namespace asio 0289 } // namespace boost 0290 0291 #include <boost/asio/detail/pop_options.hpp> 0292 0293 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) 0294 // && !defined(BOOST_ASIO_NO_TS_EXECUTORS) 0295 0296 #endif // BOOST_ASIO_IO_CONTEXT_STRAND_HPP
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |