5 // Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #ifndef BOOST_ASIO_STRAND_HPP
12 #define BOOST_ASIO_STRAND_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
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>
25 #include <boost/asio/detail/push_options.hpp>
30 /// Provides serialised handler execution.
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
36 * @par Order of handler invocation
39 * @li a strand object @c s
41 * @li an object @c a meeting completion handler requirements
43 * @li an object @c a1 which is an arbitrary copy of @c a made by the
46 * @li an object @c b meeting completion handler requirements
48 * @li an object @c b1 which is an arbitrary copy of @c b made by the
51 * if any of the following conditions are true:
53 * @li @c s.post(a) happens-before @c s.post(b)
55 * @li @c s.post(a) happens-before @c s.dispatch(b), where the latter is
56 * performed outside the strand
58 * @li @c s.dispatch(a) happens-before @c s.post(b), where the former is
59 * performed outside the strand
61 * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are
62 * performed outside the strand
64 * then @c asio_handler_invoke(a1, &a1) happens-before
65 * @c asio_handler_invoke(b1, &b1).
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.
76 * @note The implementation makes no guarantee that handlers posted or
77 * dispatched through different @c strand objects will be invoked concurrently.
80 * @e Distinct @e objects: Safe.@n
81 * @e Shared @e objects: Safe.
86 class io_service::strand
91 * Constructs the strand.
93 * @param io_service The io_service object that the strand will use to
94 * dispatch handlers that are ready to be run.
96 explicit strand(boost::asio::io_service& io_service)
97 : service_(boost::asio::use_service<
98 boost::asio::detail::strand_service>(io_service))
100 service_.construct(impl_);
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.
114 /// Get the io_service associated with the strand.
116 * This function may be used to obtain the io_service object that the strand
117 * uses to dispatch handlers for asynchronous operations.
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.
122 boost::asio::io_service& get_io_service()
124 return service_.get_io_service();
127 /// Request the strand to invoke the given handler.
129 * This function is used to ask the strand to execute the given handler.
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.
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.
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
146 template <typename CompletionHandler>
147 BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ())
148 dispatch(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler)
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;
154 detail::async_result_init<
155 CompletionHandler, void ()> init(
156 BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler));
158 service_.dispatch(impl_, init.handler);
160 return init.result.get();
163 /// Request the strand to invoke the given handler and return
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.
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.
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
179 template <typename CompletionHandler>
180 BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ())
181 post(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler)
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;
187 detail::async_result_init<
188 CompletionHandler, void ()> init(
189 BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler));
191 service_.post(impl_, init.handler);
193 return init.result.get();
196 /// Create a new handler that automatically dispatches the wrapped handler
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
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
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
217 template <typename Handler>
218 #if defined(GENERATING_DOCUMENTATION)
221 detail::wrapped_handler<strand, Handler, detail::is_continuation_if_running>
223 wrap(Handler handler)
225 return detail::wrapped_handler<io_service::strand, Handler,
226 detail::is_continuation_if_running>(*this, handler);
229 /// Determine whether the strand is running in the current thread.
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
235 bool running_in_this_thread() const
237 return service_.running_in_this_thread(impl_);
241 boost::asio::detail::strand_service& service_;
242 boost::asio::detail::strand_service::implementation_type impl_;
245 /// (Deprecated: Use boost::asio::io_service::strand.) Typedef for backwards
247 typedef boost::asio::io_service::strand strand;
252 #include <boost/asio/detail/pop_options.hpp>
254 #endif // BOOST_ASIO_STRAND_HPP