1 // 2 // strand.hpp 3 // ~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2015 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/async_result.hpp> 20 #include <boost/asio/detail/handler_type_requirements.hpp> 21 #include <boost/asio/detail/strand_service.hpp> 22 #include <boost/asio/detail/wrapped_handler.hpp> 23 #include <boost/asio/io_service.hpp> 24 25 #include <boost/asio/detail/push_options.hpp> 26 27 namespace boost { 28 namespace asio { 29 30 /// Provides serialised handler execution. 31 /** 32 * The io_service::strand class provides the ability to post and dispatch 33 * handlers with the guarantee that none of those handlers will execute 34 * concurrently. 35 * 36 * @par Order of handler invocation 37 * Given: 38 * 39 * @li a strand object @c s 40 * 41 * @li an object @c a meeting completion handler requirements 42 * 43 * @li an object @c a1 which is an arbitrary copy of @c a made by the 44 * implementation 45 * 46 * @li an object @c b meeting completion handler requirements 47 * 48 * @li an object @c b1 which is an arbitrary copy of @c b made by the 49 * implementation 50 * 51 * if any of the following conditions are true: 52 * 53 * @li @c s.post(a) happens-before @c s.post(b) 54 * 55 * @li @c s.post(a) happens-before @c s.dispatch(b), where the latter is 56 * performed outside the strand 57 * 58 * @li @c s.dispatch(a) happens-before @c s.post(b), where the former is 59 * performed outside the strand 60 * 61 * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are 62 * performed outside the strand 63 * 64 * then @c asio_handler_invoke(a1, &a1) happens-before 65 * @c asio_handler_invoke(b1, &b1). 66 * 67 * Note that in the following case: 68 * @code async_op_1(..., s.wrap(a)); 69 * async_op_2(..., s.wrap(b)); @endcode 70 * the completion of the first async operation will perform @c s.dispatch(a), 71 * and the second will perform @c s.dispatch(b), but the order in which those 72 * are performed is unspecified. That is, you cannot state whether one 73 * happens-before the other. Therefore none of the above conditions are met and 74 * no ordering guarantee is made. 75 * 76 * @note The implementation makes no guarantee that handlers posted or 77 * dispatched through different @c strand objects will be invoked concurrently. 78 * 79 * @par Thread Safety 80 * @e Distinct @e objects: Safe.@n 81 * @e Shared @e objects: Safe. 82 * 83 * @par Concepts: 84 * Dispatcher. 85 */ 86 class io_service::strand 87 { 88 public: 89 /// Constructor. 90 /** 91 * Constructs the strand. 92 * 93 * @param io_service The io_service object that the strand will use to 94 * dispatch handlers that are ready to be run. 95 */ strand(boost::asio::io_service & io_service)96 explicit strand(boost::asio::io_service& io_service) 97 : service_(boost::asio::use_service< 98 boost::asio::detail::strand_service>(io_service)) 99 { 100 service_.construct(impl_); 101 } 102 103 /// Destructor. 104 /** 105 * Destroys a strand. 106 * 107 * Handlers posted through the strand that have not yet been invoked will 108 * still be dispatched in a way that meets the guarantee of non-concurrency. 109 */ ~strand()110 ~strand() 111 { 112 } 113 114 /// Get the io_service associated with the strand. 115 /** 116 * This function may be used to obtain the io_service object that the strand 117 * uses to dispatch handlers for asynchronous operations. 118 * 119 * @return A reference to the io_service object that the strand will use to 120 * dispatch handlers. Ownership is not transferred to the caller. 121 */ get_io_service()122 boost::asio::io_service& get_io_service() 123 { 124 return service_.get_io_service(); 125 } 126 127 /// Request the strand to invoke the given handler. 128 /** 129 * This function is used to ask the strand to execute the given handler. 130 * 131 * The strand object guarantees that handlers posted or dispatched through 132 * the strand will not be executed concurrently. The handler may be executed 133 * inside this function if the guarantee can be met. If this function is 134 * called from within a handler that was posted or dispatched through the same 135 * strand, then the new handler will be executed immediately. 136 * 137 * The strand's guarantee is in addition to the guarantee provided by the 138 * underlying io_service. The io_service guarantees that the handler will only 139 * be called in a thread in which the io_service's run member function is 140 * currently being invoked. 141 * 142 * @param handler The handler to be called. The strand will make a copy of the 143 * handler object as required. The function signature of the handler must be: 144 * @code void handler(); @endcode 145 */ 146 template <typename CompletionHandler> BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler,void ())147 BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) 148 dispatch(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) 149 { 150 // If you get an error on the following line it means that your handler does 151 // not meet the documented type requirements for a CompletionHandler. 152 BOOST_ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; 153 154 detail::async_result_init< 155 CompletionHandler, void ()> init( 156 BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); 157 158 service_.dispatch(impl_, init.handler); 159 160 return init.result.get(); 161 } 162 163 /// Request the strand to invoke the given handler and return 164 /// immediately. 165 /** 166 * This function is used to ask the strand to execute the given handler, but 167 * without allowing the strand to call the handler from inside this function. 168 * 169 * The strand object guarantees that handlers posted or dispatched through 170 * the strand will not be executed concurrently. The strand's guarantee is in 171 * addition to the guarantee provided by the underlying io_service. The 172 * io_service guarantees that the handler will only be called in a thread in 173 * which the io_service's run member function is currently being invoked. 174 * 175 * @param handler The handler to be called. The strand will make a copy of the 176 * handler object as required. The function signature of the handler must be: 177 * @code void handler(); @endcode 178 */ 179 template <typename CompletionHandler> BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler,void ())180 BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) 181 post(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) 182 { 183 // If you get an error on the following line it means that your handler does 184 // not meet the documented type requirements for a CompletionHandler. 185 BOOST_ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; 186 187 detail::async_result_init< 188 CompletionHandler, void ()> init( 189 BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); 190 191 service_.post(impl_, init.handler); 192 193 return init.result.get(); 194 } 195 196 /// Create a new handler that automatically dispatches the wrapped handler 197 /// on the strand. 198 /** 199 * This function is used to create a new handler function object that, when 200 * invoked, will automatically pass the wrapped handler to the strand's 201 * dispatch function. 202 * 203 * @param handler The handler to be wrapped. The strand will make a copy of 204 * the handler object as required. The function signature of the handler must 205 * be: @code void handler(A1 a1, ... An an); @endcode 206 * 207 * @return A function object that, when invoked, passes the wrapped handler to 208 * the strand's dispatch function. Given a function object with the signature: 209 * @code R f(A1 a1, ... An an); @endcode 210 * If this function object is passed to the wrap function like so: 211 * @code strand.wrap(f); @endcode 212 * then the return value is a function object with the signature 213 * @code void g(A1 a1, ... An an); @endcode 214 * that, when invoked, executes code equivalent to: 215 * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode 216 */ 217 template <typename Handler> 218 #if defined(GENERATING_DOCUMENTATION) 219 unspecified 220 #else 221 detail::wrapped_handler<strand, Handler, detail::is_continuation_if_running> 222 #endif wrap(Handler handler)223 wrap(Handler handler) 224 { 225 return detail::wrapped_handler<io_service::strand, Handler, 226 detail::is_continuation_if_running>(*this, handler); 227 } 228 229 /// Determine whether the strand is running in the current thread. 230 /** 231 * @return @c true if the current thread is executing a handler that was 232 * submitted to the strand using post(), dispatch() or wrap(). Otherwise 233 * returns @c false. 234 */ running_in_this_thread() const235 bool running_in_this_thread() const 236 { 237 return service_.running_in_this_thread(impl_); 238 } 239 240 private: 241 boost::asio::detail::strand_service& service_; 242 boost::asio::detail::strand_service::implementation_type impl_; 243 }; 244 245 /// (Deprecated: Use boost::asio::io_service::strand.) Typedef for backwards 246 /// compatibility. 247 typedef boost::asio::io_service::strand strand; 248 249 } // namespace asio 250 } // namespace boost 251 252 #include <boost/asio/detail/pop_options.hpp> 253 254 #endif // BOOST_ASIO_STRAND_HPP 255