Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / asio / strand.hpp
1 //
2 // strand.hpp
3 // ~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2017 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>(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    */
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_);
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