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