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