Chris@16: // Chris@16: // strand.hpp Chris@16: // ~~~~~~~~~~ Chris@16: // Chris@101: // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: Chris@16: #ifndef BOOST_ASIO_STRAND_HPP Chris@16: #define BOOST_ASIO_STRAND_HPP Chris@16: Chris@16: #if defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: # pragma once Chris@16: #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace asio { Chris@16: Chris@16: /// Provides serialised handler execution. Chris@16: /** Chris@16: * The io_service::strand class provides the ability to post and dispatch Chris@16: * handlers with the guarantee that none of those handlers will execute Chris@16: * concurrently. Chris@16: * Chris@16: * @par Order of handler invocation Chris@16: * Given: Chris@16: * Chris@16: * @li a strand object @c s Chris@16: * Chris@16: * @li an object @c a meeting completion handler requirements Chris@16: * Chris@16: * @li an object @c a1 which is an arbitrary copy of @c a made by the Chris@16: * implementation Chris@16: * Chris@16: * @li an object @c b meeting completion handler requirements Chris@16: * Chris@16: * @li an object @c b1 which is an arbitrary copy of @c b made by the Chris@16: * implementation Chris@16: * Chris@16: * if any of the following conditions are true: Chris@16: * Chris@16: * @li @c s.post(a) happens-before @c s.post(b) Chris@16: * Chris@16: * @li @c s.post(a) happens-before @c s.dispatch(b), where the latter is Chris@16: * performed outside the strand Chris@16: * Chris@16: * @li @c s.dispatch(a) happens-before @c s.post(b), where the former is Chris@16: * performed outside the strand Chris@16: * Chris@16: * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are Chris@16: * performed outside the strand Chris@16: * Chris@16: * then @c asio_handler_invoke(a1, &a1) happens-before Chris@16: * @c asio_handler_invoke(b1, &b1). Chris@16: * Chris@16: * Note that in the following case: Chris@16: * @code async_op_1(..., s.wrap(a)); Chris@16: * async_op_2(..., s.wrap(b)); @endcode Chris@16: * the completion of the first async operation will perform @c s.dispatch(a), Chris@16: * and the second will perform @c s.dispatch(b), but the order in which those Chris@16: * are performed is unspecified. That is, you cannot state whether one Chris@16: * happens-before the other. Therefore none of the above conditions are met and Chris@16: * no ordering guarantee is made. Chris@16: * Chris@16: * @note The implementation makes no guarantee that handlers posted or Chris@16: * dispatched through different @c strand objects will be invoked concurrently. Chris@16: * Chris@16: * @par Thread Safety Chris@16: * @e Distinct @e objects: Safe.@n Chris@16: * @e Shared @e objects: Safe. Chris@16: * Chris@16: * @par Concepts: Chris@16: * Dispatcher. Chris@16: */ Chris@16: class io_service::strand Chris@16: { Chris@16: public: Chris@16: /// Constructor. Chris@16: /** Chris@16: * Constructs the strand. Chris@16: * Chris@16: * @param io_service The io_service object that the strand will use to Chris@16: * dispatch handlers that are ready to be run. Chris@16: */ Chris@16: explicit strand(boost::asio::io_service& io_service) Chris@16: : service_(boost::asio::use_service< Chris@16: boost::asio::detail::strand_service>(io_service)) Chris@16: { Chris@16: service_.construct(impl_); Chris@16: } Chris@16: Chris@16: /// Destructor. Chris@16: /** Chris@16: * Destroys a strand. Chris@16: * Chris@16: * Handlers posted through the strand that have not yet been invoked will Chris@16: * still be dispatched in a way that meets the guarantee of non-concurrency. Chris@16: */ Chris@16: ~strand() Chris@16: { Chris@16: } Chris@16: Chris@16: /// Get the io_service associated with the strand. Chris@16: /** Chris@16: * This function may be used to obtain the io_service object that the strand Chris@16: * uses to dispatch handlers for asynchronous operations. Chris@16: * Chris@16: * @return A reference to the io_service object that the strand will use to Chris@16: * dispatch handlers. Ownership is not transferred to the caller. Chris@16: */ Chris@16: boost::asio::io_service& get_io_service() Chris@16: { Chris@16: return service_.get_io_service(); Chris@16: } Chris@16: Chris@16: /// Request the strand to invoke the given handler. Chris@16: /** Chris@16: * This function is used to ask the strand to execute the given handler. Chris@16: * Chris@16: * The strand object guarantees that handlers posted or dispatched through Chris@16: * the strand will not be executed concurrently. The handler may be executed Chris@16: * inside this function if the guarantee can be met. If this function is Chris@16: * called from within a handler that was posted or dispatched through the same Chris@16: * strand, then the new handler will be executed immediately. Chris@16: * Chris@16: * The strand's guarantee is in addition to the guarantee provided by the Chris@16: * underlying io_service. The io_service guarantees that the handler will only Chris@16: * be called in a thread in which the io_service's run member function is Chris@16: * currently being invoked. Chris@16: * Chris@16: * @param handler The handler to be called. The strand will make a copy of the Chris@16: * handler object as required. The function signature of the handler must be: Chris@16: * @code void handler(); @endcode Chris@16: */ Chris@16: template Chris@16: BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) Chris@16: dispatch(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) Chris@16: { Chris@16: // If you get an error on the following line it means that your handler does Chris@16: // not meet the documented type requirements for a CompletionHandler. Chris@16: BOOST_ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; Chris@16: Chris@16: detail::async_result_init< Chris@16: CompletionHandler, void ()> init( Chris@16: BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); Chris@16: Chris@16: service_.dispatch(impl_, init.handler); Chris@16: Chris@16: return init.result.get(); Chris@16: } Chris@16: Chris@16: /// Request the strand to invoke the given handler and return Chris@16: /// immediately. Chris@16: /** Chris@16: * This function is used to ask the strand to execute the given handler, but Chris@16: * without allowing the strand to call the handler from inside this function. Chris@16: * Chris@16: * The strand object guarantees that handlers posted or dispatched through Chris@16: * the strand will not be executed concurrently. The strand's guarantee is in Chris@16: * addition to the guarantee provided by the underlying io_service. The Chris@16: * io_service guarantees that the handler will only be called in a thread in Chris@16: * which the io_service's run member function is currently being invoked. Chris@16: * Chris@16: * @param handler The handler to be called. The strand will make a copy of the Chris@16: * handler object as required. The function signature of the handler must be: Chris@16: * @code void handler(); @endcode Chris@16: */ Chris@16: template Chris@16: BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) Chris@16: post(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) Chris@16: { Chris@16: // If you get an error on the following line it means that your handler does Chris@16: // not meet the documented type requirements for a CompletionHandler. Chris@16: BOOST_ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; Chris@16: Chris@16: detail::async_result_init< Chris@16: CompletionHandler, void ()> init( Chris@16: BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); Chris@16: Chris@16: service_.post(impl_, init.handler); Chris@16: Chris@16: return init.result.get(); Chris@16: } Chris@16: Chris@16: /// Create a new handler that automatically dispatches the wrapped handler Chris@16: /// on the strand. Chris@16: /** Chris@16: * This function is used to create a new handler function object that, when Chris@16: * invoked, will automatically pass the wrapped handler to the strand's Chris@16: * dispatch function. Chris@16: * Chris@16: * @param handler The handler to be wrapped. The strand will make a copy of Chris@16: * the handler object as required. The function signature of the handler must Chris@16: * be: @code void handler(A1 a1, ... An an); @endcode Chris@16: * Chris@16: * @return A function object that, when invoked, passes the wrapped handler to Chris@16: * the strand's dispatch function. Given a function object with the signature: Chris@16: * @code R f(A1 a1, ... An an); @endcode Chris@16: * If this function object is passed to the wrap function like so: Chris@16: * @code strand.wrap(f); @endcode Chris@16: * then the return value is a function object with the signature Chris@16: * @code void g(A1 a1, ... An an); @endcode Chris@16: * that, when invoked, executes code equivalent to: Chris@16: * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode Chris@16: */ Chris@16: template Chris@16: #if defined(GENERATING_DOCUMENTATION) Chris@16: unspecified Chris@16: #else Chris@16: detail::wrapped_handler Chris@16: #endif Chris@16: wrap(Handler handler) Chris@16: { Chris@16: return detail::wrapped_handler(*this, handler); Chris@16: } Chris@16: Chris@16: /// Determine whether the strand is running in the current thread. Chris@16: /** Chris@16: * @return @c true if the current thread is executing a handler that was Chris@16: * submitted to the strand using post(), dispatch() or wrap(). Otherwise Chris@16: * returns @c false. Chris@16: */ Chris@16: bool running_in_this_thread() const Chris@16: { Chris@16: return service_.running_in_this_thread(impl_); Chris@16: } Chris@16: Chris@16: private: Chris@16: boost::asio::detail::strand_service& service_; Chris@16: boost::asio::detail::strand_service::implementation_type impl_; Chris@16: }; Chris@16: Chris@101: /// (Deprecated: Use boost::asio::io_service::strand.) Typedef for backwards Chris@101: /// compatibility. Chris@16: typedef boost::asio::io_service::strand strand; Chris@16: Chris@16: } // namespace asio Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_ASIO_STRAND_HPP