|
||||
File indexing completed on 2025-01-18 09:29:10
0001 // 0002 // io_context_strand.hpp 0003 // ~~~~~~~~~~~~~~~~~~~~~ 0004 // 0005 // Copyright (c) 2003-2023 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 private: 0092 #if !defined(BOOST_ASIO_NO_DEPRECATED) 0093 struct initiate_dispatch; 0094 struct initiate_post; 0095 #endif // !defined(BOOST_ASIO_NO_DEPRECATED) 0096 0097 public: 0098 /// Constructor. 0099 /** 0100 * Constructs the strand. 0101 * 0102 * @param io_context The io_context object that the strand will use to 0103 * dispatch handlers that are ready to be run. 0104 */ 0105 explicit strand(boost::asio::io_context& io_context) 0106 : service_(boost::asio::use_service< 0107 boost::asio::detail::strand_service>(io_context)) 0108 { 0109 service_.construct(impl_); 0110 } 0111 0112 /// Destructor. 0113 /** 0114 * Destroys a strand. 0115 * 0116 * Handlers posted through the strand that have not yet been invoked will 0117 * still be dispatched in a way that meets the guarantee of non-concurrency. 0118 */ 0119 ~strand() 0120 { 0121 } 0122 0123 /// Obtain the underlying execution context. 0124 boost::asio::io_context& context() const noexcept 0125 { 0126 return service_.get_io_context(); 0127 } 0128 0129 /// Inform the strand that it has some outstanding work to do. 0130 /** 0131 * The strand delegates this call to its underlying io_context. 0132 */ 0133 void on_work_started() const noexcept 0134 { 0135 context().get_executor().on_work_started(); 0136 } 0137 0138 /// Inform the strand that some work is no longer outstanding. 0139 /** 0140 * The strand delegates this call to its underlying io_context. 0141 */ 0142 void on_work_finished() const noexcept 0143 { 0144 context().get_executor().on_work_finished(); 0145 } 0146 0147 /// Request the strand to invoke the given function object. 0148 /** 0149 * This function is used to ask the strand to execute the given function 0150 * object on its underlying io_context. The function object will be executed 0151 * inside this function if the strand is not otherwise busy and if the 0152 * underlying io_context's executor's @c dispatch() function is also able to 0153 * execute the function before returning. 0154 * 0155 * @param f The function object to be called. The executor will make 0156 * a copy of the handler object as required. The function signature of the 0157 * function object must be: @code void function(); @endcode 0158 * 0159 * @param a An allocator that may be used by the executor to allocate the 0160 * internal storage needed for function invocation. 0161 */ 0162 template <typename Function, typename Allocator> 0163 void dispatch(Function&& f, const Allocator& a) const 0164 { 0165 decay_t<Function> tmp(static_cast<Function&&>(f)); 0166 service_.dispatch(impl_, tmp); 0167 (void)a; 0168 } 0169 0170 #if !defined(BOOST_ASIO_NO_DEPRECATED) 0171 /// (Deprecated: Use boost::asio::dispatch().) Request the strand to invoke 0172 /// the given handler. 0173 /** 0174 * This function is used to ask the strand to execute the given handler. 0175 * 0176 * The strand object guarantees that handlers posted or dispatched through 0177 * the strand will not be executed concurrently. The handler may be executed 0178 * inside this function if the guarantee can be met. If this function is 0179 * called from within a handler that was posted or dispatched through the same 0180 * strand, then the new handler will be executed immediately. 0181 * 0182 * The strand's guarantee is in addition to the guarantee provided by the 0183 * underlying io_context. The io_context guarantees that the handler will only 0184 * be called in a thread in which the io_context's run member function is 0185 * currently being invoked. 0186 * 0187 * @param handler The handler to be called. The strand will make a copy of the 0188 * handler object as required. The function signature of the handler must be: 0189 * @code void handler(); @endcode 0190 */ 0191 template <typename LegacyCompletionHandler> 0192 auto dispatch(LegacyCompletionHandler&& handler) 0193 -> decltype( 0194 async_initiate<LegacyCompletionHandler, void ()>( 0195 declval<initiate_dispatch>(), handler, this)) 0196 { 0197 return async_initiate<LegacyCompletionHandler, void ()>( 0198 initiate_dispatch(), handler, this); 0199 } 0200 #endif // !defined(BOOST_ASIO_NO_DEPRECATED) 0201 0202 /// Request the strand to invoke the given function object. 0203 /** 0204 * This function is used to ask the executor to execute the given function 0205 * object. The function object will never be executed inside this function. 0206 * Instead, it will be scheduled to run by the underlying io_context. 0207 * 0208 * @param f The function object to be called. The executor will make 0209 * a copy of the handler object as required. The function signature of the 0210 * function object must be: @code void function(); @endcode 0211 * 0212 * @param a An allocator that may be used by the executor to allocate the 0213 * internal storage needed for function invocation. 0214 */ 0215 template <typename Function, typename Allocator> 0216 void post(Function&& f, const Allocator& a) const 0217 { 0218 decay_t<Function> tmp(static_cast<Function&&>(f)); 0219 service_.post(impl_, tmp); 0220 (void)a; 0221 } 0222 0223 #if !defined(BOOST_ASIO_NO_DEPRECATED) 0224 /// (Deprecated: Use boost::asio::post().) Request the strand to invoke the 0225 /// given handler and return immediately. 0226 /** 0227 * This function is used to ask the strand to execute the given handler, but 0228 * without allowing the strand to call the handler from inside this function. 0229 * 0230 * The strand object guarantees that handlers posted or dispatched through 0231 * the strand will not be executed concurrently. The strand's guarantee is in 0232 * addition to the guarantee provided by the underlying io_context. The 0233 * io_context guarantees that the handler will only be called in a thread in 0234 * which the io_context's run member function is currently being invoked. 0235 * 0236 * @param handler The handler to be called. The strand will make a copy of the 0237 * handler object as required. The function signature of the handler must be: 0238 * @code void handler(); @endcode 0239 */ 0240 template <typename LegacyCompletionHandler> 0241 auto post(LegacyCompletionHandler&& handler) 0242 -> decltype( 0243 async_initiate<LegacyCompletionHandler, void ()>( 0244 declval<initiate_post>(), handler, this)) 0245 { 0246 return async_initiate<LegacyCompletionHandler, void ()>( 0247 initiate_post(), handler, this); 0248 } 0249 #endif // !defined(BOOST_ASIO_NO_DEPRECATED) 0250 0251 /// Request the strand to invoke the given function object. 0252 /** 0253 * This function is used to ask the executor to execute the given function 0254 * object. The function object will never be executed inside this function. 0255 * Instead, it will be scheduled to run by the underlying io_context. 0256 * 0257 * @param f The function object to be called. The executor will make 0258 * a copy of the handler object as required. The function signature of the 0259 * function object must be: @code void function(); @endcode 0260 * 0261 * @param a An allocator that may be used by the executor to allocate the 0262 * internal storage needed for function invocation. 0263 */ 0264 template <typename Function, typename Allocator> 0265 void defer(Function&& f, const Allocator& a) const 0266 { 0267 decay_t<Function> tmp(static_cast<Function&&>(f)); 0268 service_.post(impl_, tmp); 0269 (void)a; 0270 } 0271 0272 #if !defined(BOOST_ASIO_NO_DEPRECATED) 0273 /// (Deprecated: Use boost::asio::bind_executor().) Create a new handler that 0274 /// automatically dispatches the wrapped handler on the strand. 0275 /** 0276 * This function is used to create a new handler function object that, when 0277 * invoked, will automatically pass the wrapped handler to the strand's 0278 * dispatch function. 0279 * 0280 * @param handler The handler to be wrapped. The strand will make a copy of 0281 * the handler object as required. The function signature of the handler must 0282 * be: @code void handler(A1 a1, ... An an); @endcode 0283 * 0284 * @return A function object that, when invoked, passes the wrapped handler to 0285 * the strand's dispatch function. Given a function object with the signature: 0286 * @code R f(A1 a1, ... An an); @endcode 0287 * If this function object is passed to the wrap function like so: 0288 * @code strand.wrap(f); @endcode 0289 * then the return value is a function object with the signature 0290 * @code void g(A1 a1, ... An an); @endcode 0291 * that, when invoked, executes code equivalent to: 0292 * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode 0293 */ 0294 template <typename Handler> 0295 #if defined(GENERATING_DOCUMENTATION) 0296 unspecified 0297 #else 0298 detail::wrapped_handler<strand, Handler, detail::is_continuation_if_running> 0299 #endif 0300 wrap(Handler handler) 0301 { 0302 return detail::wrapped_handler<io_context::strand, Handler, 0303 detail::is_continuation_if_running>(*this, handler); 0304 } 0305 #endif // !defined(BOOST_ASIO_NO_DEPRECATED) 0306 0307 /// Determine whether the strand is running in the current thread. 0308 /** 0309 * @return @c true if the current thread is executing a handler that was 0310 * submitted to the strand using post(), dispatch() or wrap(). Otherwise 0311 * returns @c false. 0312 */ 0313 bool running_in_this_thread() const noexcept 0314 { 0315 return service_.running_in_this_thread(impl_); 0316 } 0317 0318 /// Compare two strands for equality. 0319 /** 0320 * Two strands are equal if they refer to the same ordered, non-concurrent 0321 * state. 0322 */ 0323 friend bool operator==(const strand& a, const strand& b) noexcept 0324 { 0325 return a.impl_ == b.impl_; 0326 } 0327 0328 /// Compare two strands for inequality. 0329 /** 0330 * Two strands are equal if they refer to the same ordered, non-concurrent 0331 * state. 0332 */ 0333 friend bool operator!=(const strand& a, const strand& b) noexcept 0334 { 0335 return a.impl_ != b.impl_; 0336 } 0337 0338 private: 0339 #if !defined(BOOST_ASIO_NO_DEPRECATED) 0340 struct initiate_dispatch 0341 { 0342 template <typename LegacyCompletionHandler> 0343 void operator()(LegacyCompletionHandler&& handler, 0344 strand* self) const 0345 { 0346 // If you get an error on the following line it means that your 0347 // handler does not meet the documented type requirements for a 0348 // LegacyCompletionHandler. 0349 BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( 0350 LegacyCompletionHandler, handler) type_check; 0351 0352 detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler); 0353 self->service_.dispatch(self->impl_, handler2.value); 0354 } 0355 }; 0356 0357 struct initiate_post 0358 { 0359 template <typename LegacyCompletionHandler> 0360 void operator()(LegacyCompletionHandler&& handler, 0361 strand* self) const 0362 { 0363 // If you get an error on the following line it means that your 0364 // handler does not meet the documented type requirements for a 0365 // LegacyCompletionHandler. 0366 BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( 0367 LegacyCompletionHandler, handler) type_check; 0368 0369 detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler); 0370 self->service_.post(self->impl_, handler2.value); 0371 } 0372 }; 0373 #endif // !defined(BOOST_ASIO_NO_DEPRECATED) 0374 0375 boost::asio::detail::strand_service& service_; 0376 mutable boost::asio::detail::strand_service::implementation_type impl_; 0377 }; 0378 0379 } // namespace asio 0380 } // namespace boost 0381 0382 #include <boost/asio/detail/pop_options.hpp> 0383 0384 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) 0385 // && !defined(BOOST_ASIO_NO_TS_EXECUTORS) 0386 0387 #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 |