Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:10

0001 //
0002 // io_context_strand.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 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   /// Destructor.
0113   /**
0114    * Destroys a strand.
0115    *
0116    * Handlers posted through the strand that have not yet been invoked will
0117    * still be dispatched in a way that meets the guarantee of non-concurrency.
0118    */
0119   ~strand()
0120   {
0121   }
0122 
0123   /// Obtain the underlying execution context.
0124   boost::asio::io_context& context() const noexcept
0125   {
0126     return service_.get_io_context();
0127   }
0128 
0129   /// Inform the strand that it has some outstanding work to do.
0130   /**
0131    * The strand delegates this call to its underlying io_context.
0132    */
0133   void on_work_started() const noexcept
0134   {
0135     context().get_executor().on_work_started();
0136   }
0137 
0138   /// Inform the strand that some work is no longer outstanding.
0139   /**
0140    * The strand delegates this call to its underlying io_context.
0141    */
0142   void on_work_finished() const noexcept
0143   {
0144     context().get_executor().on_work_finished();
0145   }
0146 
0147   /// Request the strand to invoke the given function object.
0148   /**
0149    * This function is used to ask the strand to execute the given function
0150    * object on its underlying io_context. The function object will be executed
0151    * inside this function if the strand is not otherwise busy and if the
0152    * underlying io_context's executor's @c dispatch() function is also able to
0153    * execute the function before returning.
0154    *
0155    * @param f The function object to be called. The executor will make
0156    * a copy of the handler object as required. The function signature of the
0157    * function object must be: @code void function(); @endcode
0158    *
0159    * @param a An allocator that may be used by the executor to allocate the
0160    * internal storage needed for function invocation.
0161    */
0162   template <typename Function, typename Allocator>
0163   void dispatch(Function&& f, const Allocator& a) const
0164   {
0165     decay_t<Function> tmp(static_cast<Function&&>(f));
0166     service_.dispatch(impl_, tmp);
0167     (void)a;
0168   }
0169 
0170 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0171   /// (Deprecated: Use boost::asio::dispatch().) Request the strand to invoke
0172   /// the given handler.
0173   /**
0174    * This function is used to ask the strand to execute the given handler.
0175    *
0176    * The strand object guarantees that handlers posted or dispatched through
0177    * the strand will not be executed concurrently. The handler may be executed
0178    * inside this function if the guarantee can be met. If this function is
0179    * called from within a handler that was posted or dispatched through the same
0180    * strand, then the new handler will be executed immediately.
0181    *
0182    * The strand's guarantee is in addition to the guarantee provided by the
0183    * underlying io_context. The io_context guarantees that the handler will only
0184    * be called in a thread in which the io_context's run member function is
0185    * currently being invoked.
0186    *
0187    * @param handler The handler to be called. The strand will make a copy of the
0188    * handler object as required. The function signature of the handler must be:
0189    * @code void handler(); @endcode
0190    */
0191   template <typename LegacyCompletionHandler>
0192   auto dispatch(LegacyCompletionHandler&& handler)
0193     -> decltype(
0194       async_initiate<LegacyCompletionHandler, void ()>(
0195         declval<initiate_dispatch>(), handler, this))
0196   {
0197     return async_initiate<LegacyCompletionHandler, void ()>(
0198         initiate_dispatch(), handler, this);
0199   }
0200 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0201 
0202   /// Request the strand to invoke the given function object.
0203   /**
0204    * This function is used to ask the executor to execute the given function
0205    * object. The function object will never be executed inside this function.
0206    * Instead, it will be scheduled to run by the underlying io_context.
0207    *
0208    * @param f The function object to be called. The executor will make
0209    * a copy of the handler object as required. The function signature of the
0210    * function object must be: @code void function(); @endcode
0211    *
0212    * @param a An allocator that may be used by the executor to allocate the
0213    * internal storage needed for function invocation.
0214    */
0215   template <typename Function, typename Allocator>
0216   void post(Function&& f, const Allocator& a) const
0217   {
0218     decay_t<Function> tmp(static_cast<Function&&>(f));
0219     service_.post(impl_, tmp);
0220     (void)a;
0221   }
0222 
0223 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0224   /// (Deprecated: Use boost::asio::post().) Request the strand to invoke the
0225   /// given handler and return immediately.
0226   /**
0227    * This function is used to ask the strand to execute the given handler, but
0228    * without allowing the strand to call the handler from inside this function.
0229    *
0230    * The strand object guarantees that handlers posted or dispatched through
0231    * the strand will not be executed concurrently. The strand's guarantee is in
0232    * addition to the guarantee provided by the underlying io_context. The
0233    * io_context guarantees that the handler will only be called in a thread in
0234    * which the io_context's run member function is currently being invoked.
0235    *
0236    * @param handler The handler to be called. The strand will make a copy of the
0237    * handler object as required. The function signature of the handler must be:
0238    * @code void handler(); @endcode
0239    */
0240   template <typename LegacyCompletionHandler>
0241   auto post(LegacyCompletionHandler&& handler)
0242     -> decltype(
0243       async_initiate<LegacyCompletionHandler, void ()>(
0244         declval<initiate_post>(), handler, this))
0245   {
0246     return async_initiate<LegacyCompletionHandler, void ()>(
0247         initiate_post(), handler, this);
0248   }
0249 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0250 
0251   /// Request the strand to invoke the given function object.
0252   /**
0253    * This function is used to ask the executor to execute the given function
0254    * object. The function object will never be executed inside this function.
0255    * Instead, it will be scheduled to run by the underlying io_context.
0256    *
0257    * @param f The function object to be called. The executor will make
0258    * a copy of the handler object as required. The function signature of the
0259    * function object must be: @code void function(); @endcode
0260    *
0261    * @param a An allocator that may be used by the executor to allocate the
0262    * internal storage needed for function invocation.
0263    */
0264   template <typename Function, typename Allocator>
0265   void defer(Function&& f, const Allocator& a) const
0266   {
0267     decay_t<Function> tmp(static_cast<Function&&>(f));
0268     service_.post(impl_, tmp);
0269     (void)a;
0270   }
0271 
0272 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0273   /// (Deprecated: Use boost::asio::bind_executor().) Create a new handler that
0274   /// automatically dispatches the wrapped handler on the strand.
0275   /**
0276    * This function is used to create a new handler function object that, when
0277    * invoked, will automatically pass the wrapped handler to the strand's
0278    * dispatch function.
0279    *
0280    * @param handler The handler to be wrapped. The strand will make a copy of
0281    * the handler object as required. The function signature of the handler must
0282    * be: @code void handler(A1 a1, ... An an); @endcode
0283    *
0284    * @return A function object that, when invoked, passes the wrapped handler to
0285    * the strand's dispatch function. Given a function object with the signature:
0286    * @code R f(A1 a1, ... An an); @endcode
0287    * If this function object is passed to the wrap function like so:
0288    * @code strand.wrap(f); @endcode
0289    * then the return value is a function object with the signature
0290    * @code void g(A1 a1, ... An an); @endcode
0291    * that, when invoked, executes code equivalent to:
0292    * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode
0293    */
0294   template <typename Handler>
0295 #if defined(GENERATING_DOCUMENTATION)
0296   unspecified
0297 #else
0298   detail::wrapped_handler<strand, Handler, detail::is_continuation_if_running>
0299 #endif
0300   wrap(Handler handler)
0301   {
0302     return detail::wrapped_handler<io_context::strand, Handler,
0303         detail::is_continuation_if_running>(*this, handler);
0304   }
0305 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0306 
0307   /// Determine whether the strand is running in the current thread.
0308   /**
0309    * @return @c true if the current thread is executing a handler that was
0310    * submitted to the strand using post(), dispatch() or wrap(). Otherwise
0311    * returns @c false.
0312    */
0313   bool running_in_this_thread() const noexcept
0314   {
0315     return service_.running_in_this_thread(impl_);
0316   }
0317 
0318   /// Compare two strands for equality.
0319   /**
0320    * Two strands are equal if they refer to the same ordered, non-concurrent
0321    * state.
0322    */
0323   friend bool operator==(const strand& a, const strand& b) noexcept
0324   {
0325     return a.impl_ == b.impl_;
0326   }
0327 
0328   /// Compare two strands for inequality.
0329   /**
0330    * Two strands are equal if they refer to the same ordered, non-concurrent
0331    * state.
0332    */
0333   friend bool operator!=(const strand& a, const strand& b) noexcept
0334   {
0335     return a.impl_ != b.impl_;
0336   }
0337 
0338 private:
0339 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0340   struct initiate_dispatch
0341   {
0342     template <typename LegacyCompletionHandler>
0343     void operator()(LegacyCompletionHandler&& handler,
0344         strand* self) const
0345     {
0346       // If you get an error on the following line it means that your
0347       // handler does not meet the documented type requirements for a
0348       // LegacyCompletionHandler.
0349       BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK(
0350           LegacyCompletionHandler, handler) type_check;
0351 
0352       detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);
0353       self->service_.dispatch(self->impl_, handler2.value);
0354     }
0355   };
0356 
0357   struct initiate_post
0358   {
0359     template <typename LegacyCompletionHandler>
0360     void operator()(LegacyCompletionHandler&& handler,
0361         strand* self) const
0362     {
0363       // If you get an error on the following line it means that your
0364       // handler does not meet the documented type requirements for a
0365       // LegacyCompletionHandler.
0366       BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK(
0367           LegacyCompletionHandler, handler) type_check;
0368 
0369       detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);
0370       self->service_.post(self->impl_, handler2.value);
0371     }
0372   };
0373 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0374 
0375   boost::asio::detail::strand_service& service_;
0376   mutable boost::asio::detail::strand_service::implementation_type impl_;
0377 };
0378 
0379 } // namespace asio
0380 } // namespace boost
0381 
0382 #include <boost/asio/detail/pop_options.hpp>
0383 
0384 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
0385        //   && !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0386 
0387 #endif // BOOST_ASIO_IO_CONTEXT_STRAND_HPP