Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/boost/asio/io_context_strand.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 //
0002 // io_context_strand.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_IO_CONTEXT_STRAND_HPP
0012 #define BOOST_ASIO_IO_CONTEXT_STRAND_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #if !defined(BOOST_ASIO_NO_EXTENSIONS) \
0021   && !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0022 
0023 #include <boost/asio/async_result.hpp>
0024 #include <boost/asio/detail/handler_type_requirements.hpp>
0025 #include <boost/asio/detail/strand_service.hpp>
0026 #include <boost/asio/detail/wrapped_handler.hpp>
0027 #include <boost/asio/io_context.hpp>
0028 
0029 #include <boost/asio/detail/push_options.hpp>
0030 
0031 namespace boost {
0032 namespace asio {
0033 
0034 /// Provides serialised handler execution.
0035 /**
0036  * The io_context::strand class provides the ability to post and dispatch
0037  * handlers with the guarantee that none of those handlers will execute
0038  * concurrently.
0039  *
0040  * @par Order of handler invocation
0041  * Given:
0042  *
0043  * @li a strand object @c s
0044  *
0045  * @li an object @c a meeting completion handler requirements
0046  *
0047  * @li an object @c a1 which is an arbitrary copy of @c a made by the
0048  * implementation
0049  *
0050  * @li an object @c b meeting completion handler requirements
0051  *
0052  * @li an object @c b1 which is an arbitrary copy of @c b made by the
0053  * implementation
0054  *
0055  * if any of the following conditions are true:
0056  *
0057  * @li @c s.post(a) happens-before @c s.post(b)
0058  *
0059  * @li @c s.post(a) happens-before @c s.dispatch(b), where the latter is
0060  * performed outside the strand
0061  *
0062  * @li @c s.dispatch(a) happens-before @c s.post(b), where the former is
0063  * performed outside the strand
0064  *
0065  * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are
0066  * performed outside the strand
0067  *
0068  * then @c a() happens-before @c b()
0069  *
0070  * Note that in the following case:
0071  * @code async_op_1(..., s.wrap(a));
0072  * async_op_2(..., s.wrap(b)); @endcode
0073  * the completion of the first async operation will perform @c s.dispatch(a),
0074  * and the second will perform @c s.dispatch(b), but the order in which those
0075  * are performed is unspecified. That is, you cannot state whether one
0076  * happens-before the other. Therefore none of the above conditions are met and
0077  * no ordering guarantee is made.
0078  *
0079  * @note The implementation makes no guarantee that handlers posted or
0080  * dispatched through different @c strand objects will be invoked concurrently.
0081  *
0082  * @par Thread Safety
0083  * @e Distinct @e objects: Safe.@n
0084  * @e Shared @e objects: Safe.
0085  *
0086  * @par Concepts:
0087  * Dispatcher.
0088  */
0089 class io_context::strand
0090 {
0091 private:
0092 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0093   struct initiate_dispatch;
0094   struct initiate_post;
0095 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0096 
0097 public:
0098   /// Constructor.
0099   /**
0100    * Constructs the strand.
0101    *
0102    * @param io_context The io_context object that the strand will use to
0103    * dispatch handlers that are ready to be run.
0104    */
0105   explicit strand(boost::asio::io_context& io_context)
0106     : service_(boost::asio::use_service<
0107         boost::asio::detail::strand_service>(io_context))
0108   {
0109     service_.construct(impl_);
0110   }
0111 
0112   /// Copy constructor.
0113   /**
0114    * Creates a copy such that both strand objects share the same underlying
0115    * state.
0116    */
0117   strand(const strand& other) noexcept
0118     : service_(other.service_),
0119       impl_(other.impl_)
0120   {
0121   }
0122 
0123   /// Destructor.
0124   /**
0125    * Destroys a strand.
0126    *
0127    * Handlers posted through the strand that have not yet been invoked will
0128    * still be dispatched in a way that meets the guarantee of non-concurrency.
0129    */
0130   ~strand()
0131   {
0132   }
0133 
0134   /// Obtain the underlying execution context.
0135   boost::asio::io_context& context() const noexcept
0136   {
0137     return service_.get_io_context();
0138   }
0139 
0140   /// Inform the strand that it has some outstanding work to do.
0141   /**
0142    * The strand delegates this call to its underlying io_context.
0143    */
0144   void on_work_started() const noexcept
0145   {
0146     context().get_executor().on_work_started();
0147   }
0148 
0149   /// Inform the strand that some work is no longer outstanding.
0150   /**
0151    * The strand delegates this call to its underlying io_context.
0152    */
0153   void on_work_finished() const noexcept
0154   {
0155     context().get_executor().on_work_finished();
0156   }
0157 
0158   /// Request the strand to invoke the given function object.
0159   /**
0160    * This function is used to ask the strand to execute the given function
0161    * object on its underlying io_context. The function object will be executed
0162    * inside this function if the strand is not otherwise busy and if the
0163    * underlying io_context's executor's @c dispatch() function is also able to
0164    * execute the function before returning.
0165    *
0166    * @param f The function object to be called. The executor will make
0167    * a copy of the handler object as required. The function signature of the
0168    * function object must be: @code void function(); @endcode
0169    *
0170    * @param a An allocator that may be used by the executor to allocate the
0171    * internal storage needed for function invocation.
0172    */
0173   template <typename Function, typename Allocator>
0174   void dispatch(Function&& f, const Allocator& a) const
0175   {
0176     decay_t<Function> tmp(static_cast<Function&&>(f));
0177     service_.dispatch(impl_, tmp);
0178     (void)a;
0179   }
0180 
0181 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0182   /// (Deprecated: Use boost::asio::dispatch().) Request the strand to invoke
0183   /// the given handler.
0184   /**
0185    * This function is used to ask the strand to execute the given handler.
0186    *
0187    * The strand object guarantees that handlers posted or dispatched through
0188    * the strand will not be executed concurrently. The handler may be executed
0189    * inside this function if the guarantee can be met. If this function is
0190    * called from within a handler that was posted or dispatched through the same
0191    * strand, then the new handler will be executed immediately.
0192    *
0193    * The strand's guarantee is in addition to the guarantee provided by the
0194    * underlying io_context. The io_context guarantees that the handler will only
0195    * be called in a thread in which the io_context's run member function is
0196    * currently being invoked.
0197    *
0198    * @param handler The handler to be called. The strand will make a copy of the
0199    * handler object as required. The function signature of the handler must be:
0200    * @code void handler(); @endcode
0201    */
0202   template <typename LegacyCompletionHandler>
0203   auto dispatch(LegacyCompletionHandler&& handler)
0204     -> decltype(
0205       async_initiate<LegacyCompletionHandler, void ()>(
0206         declval<initiate_dispatch>(), handler, this))
0207   {
0208     return async_initiate<LegacyCompletionHandler, void ()>(
0209         initiate_dispatch(), handler, this);
0210   }
0211 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0212 
0213   /// Request the strand to invoke the given function object.
0214   /**
0215    * This function is used to ask the executor to execute the given function
0216    * object. The function object will never be executed inside this function.
0217    * Instead, it will be scheduled to run by the underlying io_context.
0218    *
0219    * @param f The function object to be called. The executor will make
0220    * a copy of the handler object as required. The function signature of the
0221    * function object must be: @code void function(); @endcode
0222    *
0223    * @param a An allocator that may be used by the executor to allocate the
0224    * internal storage needed for function invocation.
0225    */
0226   template <typename Function, typename Allocator>
0227   void post(Function&& f, const Allocator& a) const
0228   {
0229     decay_t<Function> tmp(static_cast<Function&&>(f));
0230     service_.post(impl_, tmp);
0231     (void)a;
0232   }
0233 
0234 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0235   /// (Deprecated: Use boost::asio::post().) Request the strand to invoke the
0236   /// given handler and return immediately.
0237   /**
0238    * This function is used to ask the strand to execute the given handler, but
0239    * without allowing the strand to call the handler from inside this function.
0240    *
0241    * The strand object guarantees that handlers posted or dispatched through
0242    * the strand will not be executed concurrently. The strand's guarantee is in
0243    * addition to the guarantee provided by the underlying io_context. The
0244    * io_context guarantees that the handler will only be called in a thread in
0245    * which the io_context's run member function is currently being invoked.
0246    *
0247    * @param handler The handler to be called. The strand will make a copy of the
0248    * handler object as required. The function signature of the handler must be:
0249    * @code void handler(); @endcode
0250    */
0251   template <typename LegacyCompletionHandler>
0252   auto post(LegacyCompletionHandler&& handler)
0253     -> decltype(
0254       async_initiate<LegacyCompletionHandler, void ()>(
0255         declval<initiate_post>(), handler, this))
0256   {
0257     return async_initiate<LegacyCompletionHandler, void ()>(
0258         initiate_post(), handler, this);
0259   }
0260 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0261 
0262   /// Request the strand to invoke the given function object.
0263   /**
0264    * This function is used to ask the executor to execute the given function
0265    * object. The function object will never be executed inside this function.
0266    * Instead, it will be scheduled to run by the underlying io_context.
0267    *
0268    * @param f The function object to be called. The executor will make
0269    * a copy of the handler object as required. The function signature of the
0270    * function object must be: @code void function(); @endcode
0271    *
0272    * @param a An allocator that may be used by the executor to allocate the
0273    * internal storage needed for function invocation.
0274    */
0275   template <typename Function, typename Allocator>
0276   void defer(Function&& f, const Allocator& a) const
0277   {
0278     decay_t<Function> tmp(static_cast<Function&&>(f));
0279     service_.post(impl_, tmp);
0280     (void)a;
0281   }
0282 
0283 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0284   /// (Deprecated: Use boost::asio::bind_executor().) Create a new handler that
0285   /// automatically dispatches the wrapped handler on the strand.
0286   /**
0287    * This function is used to create a new handler function object that, when
0288    * invoked, will automatically pass the wrapped handler to the strand's
0289    * dispatch function.
0290    *
0291    * @param handler The handler to be wrapped. The strand will make a copy of
0292    * the handler object as required. The function signature of the handler must
0293    * be: @code void handler(A1 a1, ... An an); @endcode
0294    *
0295    * @return A function object that, when invoked, passes the wrapped handler to
0296    * the strand's dispatch function. Given a function object with the signature:
0297    * @code R f(A1 a1, ... An an); @endcode
0298    * If this function object is passed to the wrap function like so:
0299    * @code strand.wrap(f); @endcode
0300    * then the return value is a function object with the signature
0301    * @code void g(A1 a1, ... An an); @endcode
0302    * that, when invoked, executes code equivalent to:
0303    * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode
0304    */
0305   template <typename Handler>
0306 #if defined(GENERATING_DOCUMENTATION)
0307   unspecified
0308 #else
0309   detail::wrapped_handler<strand, Handler, detail::is_continuation_if_running>
0310 #endif
0311   wrap(Handler handler)
0312   {
0313     return detail::wrapped_handler<io_context::strand, Handler,
0314         detail::is_continuation_if_running>(*this, handler);
0315   }
0316 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0317 
0318   /// Determine whether the strand is running in the current thread.
0319   /**
0320    * @return @c true if the current thread is executing a handler that was
0321    * submitted to the strand using post(), dispatch() or wrap(). Otherwise
0322    * returns @c false.
0323    */
0324   bool running_in_this_thread() const noexcept
0325   {
0326     return service_.running_in_this_thread(impl_);
0327   }
0328 
0329   /// Compare two strands for equality.
0330   /**
0331    * Two strands are equal if they refer to the same ordered, non-concurrent
0332    * state.
0333    */
0334   friend bool operator==(const strand& a, const strand& b) noexcept
0335   {
0336     return a.impl_ == b.impl_;
0337   }
0338 
0339   /// Compare two strands for inequality.
0340   /**
0341    * Two strands are equal if they refer to the same ordered, non-concurrent
0342    * state.
0343    */
0344   friend bool operator!=(const strand& a, const strand& b) noexcept
0345   {
0346     return a.impl_ != b.impl_;
0347   }
0348 
0349 private:
0350 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0351   struct initiate_dispatch
0352   {
0353     template <typename LegacyCompletionHandler>
0354     void operator()(LegacyCompletionHandler&& handler,
0355         strand* self) const
0356     {
0357       // If you get an error on the following line it means that your
0358       // handler does not meet the documented type requirements for a
0359       // LegacyCompletionHandler.
0360       BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK(
0361           LegacyCompletionHandler, handler) type_check;
0362 
0363       detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);
0364       self->service_.dispatch(self->impl_, handler2.value);
0365     }
0366   };
0367 
0368   struct initiate_post
0369   {
0370     template <typename LegacyCompletionHandler>
0371     void operator()(LegacyCompletionHandler&& handler,
0372         strand* self) const
0373     {
0374       // If you get an error on the following line it means that your
0375       // handler does not meet the documented type requirements for a
0376       // LegacyCompletionHandler.
0377       BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK(
0378           LegacyCompletionHandler, handler) type_check;
0379 
0380       detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);
0381       self->service_.post(self->impl_, handler2.value);
0382     }
0383   };
0384 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0385 
0386   boost::asio::detail::strand_service& service_;
0387   mutable boost::asio::detail::strand_service::implementation_type impl_;
0388 };
0389 
0390 } // namespace asio
0391 } // namespace boost
0392 
0393 #include <boost/asio/detail/pop_options.hpp>
0394 
0395 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
0396        //   && !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0397 
0398 #endif // BOOST_ASIO_IO_CONTEXT_STRAND_HPP