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 | */ |
96 | explicit strand(boost::asio::io_service& io_service) |
97 | : service_(boost::asio::use_service< |
98 | boost::asio::detail::strand_service>(ios&: io_service)) |
99 | { |
100 | service_.construct(impl&: 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 | */ |
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 | */ |
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> |
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> |
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 |
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 | */ |
235 | bool running_in_this_thread() const |
236 | { |
237 | return service_.running_in_this_thread(impl: 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 | |