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