Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //
0002 // 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_STRAND_HPP
0012 #define BOOST_ASIO_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 #include <boost/asio/detail/strand_executor_service.hpp>
0020 #include <boost/asio/detail/type_traits.hpp>
0021 #include <boost/asio/execution/blocking.hpp>
0022 #include <boost/asio/execution/executor.hpp>
0023 #include <boost/asio/is_executor.hpp>
0024 
0025 #include <boost/asio/detail/push_options.hpp>
0026 
0027 namespace boost {
0028 namespace asio {
0029 
0030 /// Provides serialised function invocation for any executor type.
0031 template <typename Executor>
0032 class strand
0033 {
0034 public:
0035   /// The type of the underlying executor.
0036   typedef Executor inner_executor_type;
0037 
0038   /// Default constructor.
0039   /**
0040    * This constructor is only valid if the underlying executor type is default
0041    * constructible.
0042    */
0043   strand()
0044     : executor_(),
0045       impl_(strand::create_implementation(executor_))
0046   {
0047   }
0048 
0049   /// Construct a strand for the specified executor.
0050   template <typename Executor1>
0051   explicit strand(const Executor1& e,
0052       constraint_t<
0053         conditional_t<
0054           !is_same<Executor1, strand>::value,
0055           is_convertible<Executor1, Executor>,
0056           false_type
0057         >::value
0058       > = 0)
0059     : executor_(e),
0060       impl_(strand::create_implementation(executor_))
0061   {
0062   }
0063 
0064   /// Copy constructor.
0065   strand(const strand& other) noexcept
0066     : executor_(other.executor_),
0067       impl_(other.impl_)
0068   {
0069   }
0070 
0071   /// Converting constructor.
0072   /**
0073    * This constructor is only valid if the @c OtherExecutor type is convertible
0074    * to @c Executor.
0075    */
0076   template <class OtherExecutor>
0077   strand(
0078       const strand<OtherExecutor>& other) noexcept
0079     : executor_(other.executor_),
0080       impl_(other.impl_)
0081   {
0082   }
0083 
0084   /// Assignment operator.
0085   strand& operator=(const strand& other) noexcept
0086   {
0087     executor_ = other.executor_;
0088     impl_ = other.impl_;
0089     return *this;
0090   }
0091 
0092   /// Converting assignment operator.
0093   /**
0094    * This assignment operator is only valid if the @c OtherExecutor type is
0095    * convertible to @c Executor.
0096    */
0097   template <class OtherExecutor>
0098   strand& operator=(
0099       const strand<OtherExecutor>& other) noexcept
0100   {
0101     executor_ = other.executor_;
0102     impl_ = other.impl_;
0103     return *this;
0104   }
0105 
0106   /// Move constructor.
0107   strand(strand&& other) noexcept
0108     : executor_(static_cast<Executor&&>(other.executor_)),
0109       impl_(static_cast<implementation_type&&>(other.impl_))
0110   {
0111   }
0112 
0113   /// Converting move constructor.
0114   /**
0115    * This constructor is only valid if the @c OtherExecutor type is convertible
0116    * to @c Executor.
0117    */
0118   template <class OtherExecutor>
0119   strand(strand<OtherExecutor>&& other) noexcept
0120     : executor_(static_cast<OtherExecutor&&>(other.executor_)),
0121       impl_(static_cast<implementation_type&&>(other.impl_))
0122   {
0123   }
0124 
0125   /// Move assignment operator.
0126   strand& operator=(strand&& other) noexcept
0127   {
0128     executor_ = static_cast<Executor&&>(other.executor_);
0129     impl_ = static_cast<implementation_type&&>(other.impl_);
0130     return *this;
0131   }
0132 
0133   /// Converting move assignment operator.
0134   /**
0135    * This assignment operator is only valid if the @c OtherExecutor type is
0136    * convertible to @c Executor.
0137    */
0138   template <class OtherExecutor>
0139   strand& operator=(strand<OtherExecutor>&& other) noexcept
0140   {
0141     executor_ = static_cast<OtherExecutor&&>(other.executor_);
0142     impl_ = static_cast<implementation_type&&>(other.impl_);
0143     return *this;
0144   }
0145 
0146   /// Destructor.
0147   ~strand() noexcept
0148   {
0149   }
0150 
0151   /// Obtain the underlying executor.
0152   inner_executor_type get_inner_executor() const noexcept
0153   {
0154     return executor_;
0155   }
0156 
0157   /// Forward a query to the underlying executor.
0158   /**
0159    * Do not call this function directly. It is intended for use with the
0160    * boost::asio::query customisation point.
0161    *
0162    * For example:
0163    * @code boost::asio::strand<my_executor_type> ex = ...;
0164    * if (boost::asio::query(ex, boost::asio::execution::blocking)
0165    *       == boost::asio::execution::blocking.never)
0166    *   ... @endcode
0167    */
0168   template <typename Property>
0169   constraint_t<
0170     can_query<const Executor&, Property>::value,
0171     conditional_t<
0172       is_convertible<Property, execution::blocking_t>::value,
0173       execution::blocking_t,
0174       query_result_t<const Executor&, Property>
0175     >
0176   > query(const Property& p) const
0177     noexcept(is_nothrow_query<const Executor&, Property>::value)
0178   {
0179     return this->query_helper(
0180         is_convertible<Property, execution::blocking_t>(), p);
0181   }
0182 
0183   /// Forward a requirement to the underlying executor.
0184   /**
0185    * Do not call this function directly. It is intended for use with the
0186    * boost::asio::require customisation point.
0187    *
0188    * For example:
0189    * @code boost::asio::strand<my_executor_type> ex1 = ...;
0190    * auto ex2 = boost::asio::require(ex1,
0191    *     boost::asio::execution::blocking.never); @endcode
0192    */
0193   template <typename Property>
0194   constraint_t<
0195     can_require<const Executor&, Property>::value
0196       && !is_convertible<Property, execution::blocking_t::always_t>::value,
0197     strand<decay_t<require_result_t<const Executor&, Property>>>
0198   > require(const Property& p) const
0199     noexcept(is_nothrow_require<const Executor&, Property>::value)
0200   {
0201     return strand<decay_t<require_result_t<const Executor&, Property>>>(
0202         boost::asio::require(executor_, p), impl_);
0203   }
0204 
0205   /// Forward a preference to the underlying executor.
0206   /**
0207    * Do not call this function directly. It is intended for use with the
0208    * boost::asio::prefer customisation point.
0209    *
0210    * For example:
0211    * @code boost::asio::strand<my_executor_type> ex1 = ...;
0212    * auto ex2 = boost::asio::prefer(ex1,
0213    *     boost::asio::execution::blocking.never); @endcode
0214    */
0215   template <typename Property>
0216   constraint_t<
0217     can_prefer<const Executor&, Property>::value
0218       && !is_convertible<Property, execution::blocking_t::always_t>::value,
0219     strand<decay_t<prefer_result_t<const Executor&, Property>>>
0220   > prefer(const Property& p) const
0221     noexcept(is_nothrow_prefer<const Executor&, Property>::value)
0222   {
0223     return strand<decay_t<prefer_result_t<const Executor&, Property>>>(
0224         boost::asio::prefer(executor_, p), impl_);
0225   }
0226 
0227 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0228   /// Obtain the underlying execution context.
0229   execution_context& context() const noexcept
0230   {
0231     return executor_.context();
0232   }
0233 
0234   /// Inform the strand that it has some outstanding work to do.
0235   /**
0236    * The strand delegates this call to its underlying executor.
0237    */
0238   void on_work_started() const noexcept
0239   {
0240     executor_.on_work_started();
0241   }
0242 
0243   /// Inform the strand that some work is no longer outstanding.
0244   /**
0245    * The strand delegates this call to its underlying executor.
0246    */
0247   void on_work_finished() const noexcept
0248   {
0249     executor_.on_work_finished();
0250   }
0251 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0252 
0253   /// Request the strand to invoke the given function object.
0254   /**
0255    * This function is used to ask the strand to execute the given function
0256    * object on its underlying executor. The function object will be executed
0257    * according to the properties of the underlying executor.
0258    *
0259    * @param f The function object to be called. The executor will make
0260    * a copy of the handler object as required. The function signature of the
0261    * function object must be: @code void function(); @endcode
0262    */
0263   template <typename Function>
0264   constraint_t<
0265     traits::execute_member<const Executor&, Function>::is_valid,
0266     void
0267   > execute(Function&& f) const
0268   {
0269     detail::strand_executor_service::execute(impl_,
0270         executor_, static_cast<Function&&>(f));
0271   }
0272 
0273 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0274   /// Request the strand to invoke the given function object.
0275   /**
0276    * This function is used to ask the strand to execute the given function
0277    * object on its underlying executor. The function object will be executed
0278    * inside this function if the strand is not otherwise busy and if the
0279    * underlying executor's @c dispatch() function is also able to execute the
0280    * function before returning.
0281    *
0282    * @param f The function object to be called. The executor will make
0283    * a copy of the handler object as required. The function signature of the
0284    * function object must be: @code void function(); @endcode
0285    *
0286    * @param a An allocator that may be used by the executor to allocate the
0287    * internal storage needed for function invocation.
0288    */
0289   template <typename Function, typename Allocator>
0290   void dispatch(Function&& f, const Allocator& a) const
0291   {
0292     detail::strand_executor_service::dispatch(impl_,
0293         executor_, static_cast<Function&&>(f), a);
0294   }
0295 
0296   /// Request the strand to invoke the given function object.
0297   /**
0298    * This function is used to ask the executor to execute the given function
0299    * object. The function object will never be executed inside this function.
0300    * Instead, it will be scheduled by the underlying executor's defer function.
0301    *
0302    * @param f The function object to be called. The executor will make
0303    * a copy of the handler object as required. The function signature of the
0304    * function object must be: @code void function(); @endcode
0305    *
0306    * @param a An allocator that may be used by the executor to allocate the
0307    * internal storage needed for function invocation.
0308    */
0309   template <typename Function, typename Allocator>
0310   void post(Function&& f, const Allocator& a) const
0311   {
0312     detail::strand_executor_service::post(impl_,
0313         executor_, static_cast<Function&&>(f), a);
0314   }
0315 
0316   /// Request the strand to invoke the given function object.
0317   /**
0318    * This function is used to ask the executor to execute the given function
0319    * object. The function object will never be executed inside this function.
0320    * Instead, it will be scheduled by the underlying executor's defer function.
0321    *
0322    * @param f The function object to be called. The executor will make
0323    * a copy of the handler object as required. The function signature of the
0324    * function object must be: @code void function(); @endcode
0325    *
0326    * @param a An allocator that may be used by the executor to allocate the
0327    * internal storage needed for function invocation.
0328    */
0329   template <typename Function, typename Allocator>
0330   void defer(Function&& f, const Allocator& a) const
0331   {
0332     detail::strand_executor_service::defer(impl_,
0333         executor_, static_cast<Function&&>(f), a);
0334   }
0335 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0336 
0337   /// Determine whether the strand is running in the current thread.
0338   /**
0339    * @return @c true if the current thread is executing a function that was
0340    * submitted to the strand using post(), dispatch() or defer(). Otherwise
0341    * returns @c false.
0342    */
0343   bool running_in_this_thread() const noexcept
0344   {
0345     return detail::strand_executor_service::running_in_this_thread(impl_);
0346   }
0347 
0348   /// Compare two strands for equality.
0349   /**
0350    * Two strands are equal if they refer to the same ordered, non-concurrent
0351    * state.
0352    */
0353   friend bool operator==(const strand& a, const strand& b) noexcept
0354   {
0355     return a.impl_ == b.impl_;
0356   }
0357 
0358   /// Compare two strands for inequality.
0359   /**
0360    * Two strands are equal if they refer to the same ordered, non-concurrent
0361    * state.
0362    */
0363   friend bool operator!=(const strand& a, const strand& b) noexcept
0364   {
0365     return a.impl_ != b.impl_;
0366   }
0367 
0368 #if defined(GENERATING_DOCUMENTATION)
0369 private:
0370 #endif // defined(GENERATING_DOCUMENTATION)
0371   typedef detail::strand_executor_service::implementation_type
0372     implementation_type;
0373 
0374   template <typename InnerExecutor>
0375   static implementation_type create_implementation(const InnerExecutor& ex,
0376       constraint_t<
0377         can_query<InnerExecutor, execution::context_t>::value
0378       > = 0)
0379   {
0380     return use_service<detail::strand_executor_service>(
0381         boost::asio::query(ex, execution::context)).create_implementation();
0382   }
0383 
0384   template <typename InnerExecutor>
0385   static implementation_type create_implementation(const InnerExecutor& ex,
0386       constraint_t<
0387         !can_query<InnerExecutor, execution::context_t>::value
0388       > = 0)
0389   {
0390     return use_service<detail::strand_executor_service>(
0391         ex.context()).create_implementation();
0392   }
0393 
0394   strand(const Executor& ex, const implementation_type& impl)
0395     : executor_(ex),
0396       impl_(impl)
0397   {
0398   }
0399 
0400   template <typename Property>
0401   query_result_t<const Executor&, Property> query_helper(
0402       false_type, const Property& property) const
0403   {
0404     return boost::asio::query(executor_, property);
0405   }
0406 
0407   template <typename Property>
0408   execution::blocking_t query_helper(true_type, const Property& property) const
0409   {
0410     execution::blocking_t result = boost::asio::query(executor_, property);
0411     return result == execution::blocking.always
0412       ? execution::blocking.possibly : result;
0413   }
0414 
0415   Executor executor_;
0416   implementation_type impl_;
0417 };
0418 
0419 /** @defgroup make_strand boost::asio::make_strand
0420  *
0421  * @brief The boost::asio::make_strand function creates a @ref strand object for
0422  * an executor or execution context.
0423  */
0424 /*@{*/
0425 
0426 /// Create a @ref strand object for an executor.
0427 /**
0428  * @param ex An executor.
0429  *
0430  * @returns A strand constructed with the specified executor.
0431  */
0432 template <typename Executor>
0433 inline strand<Executor> make_strand(const Executor& ex,
0434     constraint_t<
0435       is_executor<Executor>::value || execution::is_executor<Executor>::value
0436     > = 0)
0437 {
0438   return strand<Executor>(ex);
0439 }
0440 
0441 /// Create a @ref strand object for an execution context.
0442 /**
0443  * @param ctx An execution context, from which an executor will be obtained.
0444  *
0445  * @returns A strand constructed with the execution context's executor, obtained
0446  * by performing <tt>ctx.get_executor()</tt>.
0447  */
0448 template <typename ExecutionContext>
0449 inline strand<typename ExecutionContext::executor_type>
0450 make_strand(ExecutionContext& ctx,
0451     constraint_t<
0452       is_convertible<ExecutionContext&, execution_context&>::value
0453     > = 0)
0454 {
0455   return strand<typename ExecutionContext::executor_type>(ctx.get_executor());
0456 }
0457 
0458 /*@}*/
0459 
0460 #if !defined(GENERATING_DOCUMENTATION)
0461 
0462 namespace traits {
0463 
0464 #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
0465 
0466 template <typename Executor>
0467 struct equality_comparable<strand<Executor>>
0468 {
0469   static constexpr bool is_valid = true;
0470   static constexpr bool is_noexcept = true;
0471 };
0472 
0473 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
0474 
0475 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
0476 
0477 template <typename Executor, typename Function>
0478 struct execute_member<strand<Executor>, Function,
0479     enable_if_t<
0480       traits::execute_member<const Executor&, Function>::is_valid
0481     >>
0482 {
0483   static constexpr bool is_valid = true;
0484   static constexpr bool is_noexcept = false;
0485   typedef void result_type;
0486 };
0487 
0488 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
0489 
0490 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
0491 
0492 template <typename Executor, typename Property>
0493 struct query_member<strand<Executor>, Property,
0494     enable_if_t<
0495       can_query<const Executor&, Property>::value
0496     >>
0497 {
0498   static constexpr bool is_valid = true;
0499   static constexpr bool is_noexcept =
0500     is_nothrow_query<Executor, Property>::value;
0501   typedef conditional_t<
0502     is_convertible<Property, execution::blocking_t>::value,
0503       execution::blocking_t, query_result_t<Executor, Property>> result_type;
0504 };
0505 
0506 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
0507 
0508 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
0509 
0510 template <typename Executor, typename Property>
0511 struct require_member<strand<Executor>, Property,
0512     enable_if_t<
0513       can_require<const Executor&, Property>::value
0514         && !is_convertible<Property, execution::blocking_t::always_t>::value
0515     >>
0516 {
0517   static constexpr bool is_valid = true;
0518   static constexpr bool is_noexcept =
0519     is_nothrow_require<Executor, Property>::value;
0520   typedef strand<decay_t<require_result_t<Executor, Property>>> result_type;
0521 };
0522 
0523 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
0524 
0525 #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
0526 
0527 template <typename Executor, typename Property>
0528 struct prefer_member<strand<Executor>, Property,
0529     enable_if_t<
0530       can_prefer<const Executor&, Property>::value
0531         && !is_convertible<Property, execution::blocking_t::always_t>::value
0532     >>
0533 {
0534   static constexpr bool is_valid = true;
0535   static constexpr bool is_noexcept =
0536     is_nothrow_prefer<Executor, Property>::value;
0537   typedef strand<decay_t<prefer_result_t<Executor, Property>>> result_type;
0538 };
0539 
0540 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
0541 
0542 } // namespace traits
0543 
0544 #endif // !defined(GENERATING_DOCUMENTATION)
0545 
0546 } // namespace asio
0547 } // namespace boost
0548 
0549 #include <boost/asio/detail/pop_options.hpp>
0550 
0551 // If both io_context.hpp and strand.hpp have been included, automatically
0552 // include the header file needed for the io_context::strand class.
0553 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
0554 # if defined(BOOST_ASIO_IO_CONTEXT_HPP)
0555 #  include <boost/asio/io_context_strand.hpp>
0556 # endif // defined(BOOST_ASIO_IO_CONTEXT_HPP)
0557 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
0558 
0559 #endif // BOOST_ASIO_STRAND_HPP