123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571 |
- //
- // strand.hpp
- // ~~~~~~~~~~
- //
- // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- #ifndef BOOST_ASIO_STRAND_HPP
- #define BOOST_ASIO_STRAND_HPP
- #if defined(_MSC_VER) && (_MSC_VER >= 1200)
- # pragma once
- #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
- #include <boost/asio/detail/config.hpp>
- #include <boost/asio/detail/strand_executor_service.hpp>
- #include <boost/asio/detail/type_traits.hpp>
- #include <boost/asio/execution/blocking.hpp>
- #include <boost/asio/execution/executor.hpp>
- #include <boost/asio/is_executor.hpp>
- #include <boost/asio/detail/push_options.hpp>
- namespace boost {
- namespace asio {
- /// Provides serialised function invocation for any executor type.
- template <typename Executor>
- class strand
- {
- public:
- /// The type of the underlying executor.
- typedef Executor inner_executor_type;
- /// Default constructor.
- /**
- * This constructor is only valid if the underlying executor type is default
- * constructible.
- */
- strand()
- : executor_(),
- impl_(strand::create_implementation(executor_))
- {
- }
- /// Construct a strand for the specified executor.
- template <typename Executor1>
- explicit strand(const Executor1& e,
- typename constraint<
- conditional<
- !is_same<Executor1, strand>::value,
- is_convertible<Executor1, Executor>,
- false_type
- >::type::value
- >::type = 0)
- : executor_(e),
- impl_(strand::create_implementation(executor_))
- {
- }
- /// Copy constructor.
- strand(const strand& other) BOOST_ASIO_NOEXCEPT
- : executor_(other.executor_),
- impl_(other.impl_)
- {
- }
- /// Converting constructor.
- /**
- * This constructor is only valid if the @c OtherExecutor type is convertible
- * to @c Executor.
- */
- template <class OtherExecutor>
- strand(
- const strand<OtherExecutor>& other) BOOST_ASIO_NOEXCEPT
- : executor_(other.executor_),
- impl_(other.impl_)
- {
- }
- /// Assignment operator.
- strand& operator=(const strand& other) BOOST_ASIO_NOEXCEPT
- {
- executor_ = other.executor_;
- impl_ = other.impl_;
- return *this;
- }
- /// Converting assignment operator.
- /**
- * This assignment operator is only valid if the @c OtherExecutor type is
- * convertible to @c Executor.
- */
- template <class OtherExecutor>
- strand& operator=(
- const strand<OtherExecutor>& other) BOOST_ASIO_NOEXCEPT
- {
- executor_ = other.executor_;
- impl_ = other.impl_;
- return *this;
- }
- #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
- /// Move constructor.
- strand(strand&& other) BOOST_ASIO_NOEXCEPT
- : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)),
- impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_))
- {
- }
- /// Converting move constructor.
- /**
- * This constructor is only valid if the @c OtherExecutor type is convertible
- * to @c Executor.
- */
- template <class OtherExecutor>
- strand(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT
- : executor_(BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.executor_)),
- impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_))
- {
- }
- /// Move assignment operator.
- strand& operator=(strand&& other) BOOST_ASIO_NOEXCEPT
- {
- executor_ = BOOST_ASIO_MOVE_CAST(Executor)(other.executor_);
- impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_);
- return *this;
- }
- /// Converting move assignment operator.
- /**
- * This assignment operator is only valid if the @c OtherExecutor type is
- * convertible to @c Executor.
- */
- template <class OtherExecutor>
- strand& operator=(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT
- {
- executor_ = BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.executor_);
- impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_);
- return *this;
- }
- #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
- /// Destructor.
- ~strand() BOOST_ASIO_NOEXCEPT
- {
- }
- /// Obtain the underlying executor.
- inner_executor_type get_inner_executor() const BOOST_ASIO_NOEXCEPT
- {
- return executor_;
- }
- /// Forward a query to the underlying executor.
- /**
- * Do not call this function directly. It is intended for use with the
- * boost::asio::query customisation point.
- *
- * For example:
- * @code boost::asio::strand<my_executor_type> ex = ...;
- * if (boost::asio::query(ex, boost::asio::execution::blocking)
- * == boost::asio::execution::blocking.never)
- * ... @endcode
- */
- template <typename Property>
- typename constraint<
- can_query<const Executor&, Property>::value,
- typename conditional<
- is_convertible<Property, execution::blocking_t>::value,
- execution::blocking_t,
- typename query_result<const Executor&, Property>::type
- >::type
- >::type query(const Property& p) const
- BOOST_ASIO_NOEXCEPT_IF((
- is_nothrow_query<const Executor&, Property>::value))
- {
- return this->query_helper(
- is_convertible<Property, execution::blocking_t>(), p);
- }
- /// Forward a requirement to the underlying executor.
- /**
- * Do not call this function directly. It is intended for use with the
- * boost::asio::require customisation point.
- *
- * For example:
- * @code boost::asio::strand<my_executor_type> ex1 = ...;
- * auto ex2 = boost::asio::require(ex1,
- * boost::asio::execution::blocking.never); @endcode
- */
- template <typename Property>
- typename constraint<
- can_require<const Executor&, Property>::value
- && !is_convertible<Property, execution::blocking_t::always_t>::value,
- strand<typename decay<
- typename require_result<const Executor&, Property>::type
- >::type>
- >::type require(const Property& p) const
- BOOST_ASIO_NOEXCEPT_IF((
- is_nothrow_require<const Executor&, Property>::value))
- {
- return strand<typename decay<
- typename require_result<const Executor&, Property>::type
- >::type>(boost::asio::require(executor_, p), impl_);
- }
- /// Forward a preference to the underlying executor.
- /**
- * Do not call this function directly. It is intended for use with the
- * boost::asio::prefer customisation point.
- *
- * For example:
- * @code boost::asio::strand<my_executor_type> ex1 = ...;
- * auto ex2 = boost::asio::prefer(ex1,
- * boost::asio::execution::blocking.never); @endcode
- */
- template <typename Property>
- typename constraint<
- can_prefer<const Executor&, Property>::value
- && !is_convertible<Property, execution::blocking_t::always_t>::value,
- strand<typename decay<
- typename prefer_result<const Executor&, Property>::type
- >::type>
- >::type prefer(const Property& p) const
- BOOST_ASIO_NOEXCEPT_IF((
- is_nothrow_prefer<const Executor&, Property>::value))
- {
- return strand<typename decay<
- typename prefer_result<const Executor&, Property>::type
- >::type>(boost::asio::prefer(executor_, p), impl_);
- }
- #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
- /// Obtain the underlying execution context.
- execution_context& context() const BOOST_ASIO_NOEXCEPT
- {
- return executor_.context();
- }
- /// Inform the strand that it has some outstanding work to do.
- /**
- * The strand delegates this call to its underlying executor.
- */
- void on_work_started() const BOOST_ASIO_NOEXCEPT
- {
- executor_.on_work_started();
- }
- /// Inform the strand that some work is no longer outstanding.
- /**
- * The strand delegates this call to its underlying executor.
- */
- void on_work_finished() const BOOST_ASIO_NOEXCEPT
- {
- executor_.on_work_finished();
- }
- #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
- /// Request the strand to invoke the given function object.
- /**
- * Do not call this function directly. It is intended for use with the
- * execution::execute customisation point.
- *
- * For example:
- * @code boost::asio::strand<my_executor_type> ex = ...;
- * execution::execute(ex, my_function_object); @endcode
- *
- * This function is used to ask the strand to execute the given function
- * object on its underlying executor. The function object will be executed
- * according to the properties of the underlying executor.
- *
- * @param f The function object to be called. The executor will make
- * a copy of the handler object as required. The function signature of the
- * function object must be: @code void function(); @endcode
- */
- template <typename Function>
- typename constraint<
- execution::can_execute<const Executor&, Function>::value,
- void
- >::type execute(BOOST_ASIO_MOVE_ARG(Function) f) const
- {
- detail::strand_executor_service::execute(impl_,
- executor_, BOOST_ASIO_MOVE_CAST(Function)(f));
- }
- #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
- /// Request the strand to invoke the given function object.
- /**
- * This function is used to ask the strand to execute the given function
- * object on its underlying executor. The function object will be executed
- * inside this function if the strand is not otherwise busy and if the
- * underlying executor's @c dispatch() function is also able to execute the
- * function before returning.
- *
- * @param f The function object to be called. The executor will make
- * a copy of the handler object as required. The function signature of the
- * function object must be: @code void function(); @endcode
- *
- * @param a An allocator that may be used by the executor to allocate the
- * internal storage needed for function invocation.
- */
- template <typename Function, typename Allocator>
- void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
- {
- detail::strand_executor_service::dispatch(impl_,
- executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
- }
- /// Request the strand to invoke the given function object.
- /**
- * This function is used to ask the executor to execute the given function
- * object. The function object will never be executed inside this function.
- * Instead, it will be scheduled by the underlying executor's defer function.
- *
- * @param f The function object to be called. The executor will make
- * a copy of the handler object as required. The function signature of the
- * function object must be: @code void function(); @endcode
- *
- * @param a An allocator that may be used by the executor to allocate the
- * internal storage needed for function invocation.
- */
- template <typename Function, typename Allocator>
- void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
- {
- detail::strand_executor_service::post(impl_,
- executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
- }
- /// Request the strand to invoke the given function object.
- /**
- * This function is used to ask the executor to execute the given function
- * object. The function object will never be executed inside this function.
- * Instead, it will be scheduled by the underlying executor's defer function.
- *
- * @param f The function object to be called. The executor will make
- * a copy of the handler object as required. The function signature of the
- * function object must be: @code void function(); @endcode
- *
- * @param a An allocator that may be used by the executor to allocate the
- * internal storage needed for function invocation.
- */
- template <typename Function, typename Allocator>
- void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
- {
- detail::strand_executor_service::defer(impl_,
- executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
- }
- #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
- /// Determine whether the strand is running in the current thread.
- /**
- * @return @c true if the current thread is executing a function that was
- * submitted to the strand using post(), dispatch() or defer(). Otherwise
- * returns @c false.
- */
- bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT
- {
- return detail::strand_executor_service::running_in_this_thread(impl_);
- }
- /// Compare two strands for equality.
- /**
- * Two strands are equal if they refer to the same ordered, non-concurrent
- * state.
- */
- friend bool operator==(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT
- {
- return a.impl_ == b.impl_;
- }
- /// Compare two strands for inequality.
- /**
- * Two strands are equal if they refer to the same ordered, non-concurrent
- * state.
- */
- friend bool operator!=(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT
- {
- return a.impl_ != b.impl_;
- }
- #if defined(GENERATING_DOCUMENTATION)
- private:
- #endif // defined(GENERATING_DOCUMENTATION)
- typedef detail::strand_executor_service::implementation_type
- implementation_type;
- template <typename InnerExecutor>
- static implementation_type create_implementation(const InnerExecutor& ex,
- typename constraint<
- can_query<InnerExecutor, execution::context_t>::value
- >::type = 0)
- {
- return use_service<detail::strand_executor_service>(
- boost::asio::query(ex, execution::context)).create_implementation();
- }
- template <typename InnerExecutor>
- static implementation_type create_implementation(const InnerExecutor& ex,
- typename constraint<
- !can_query<InnerExecutor, execution::context_t>::value
- >::type = 0)
- {
- return use_service<detail::strand_executor_service>(
- ex.context()).create_implementation();
- }
- strand(const Executor& ex, const implementation_type& impl)
- : executor_(ex),
- impl_(impl)
- {
- }
- template <typename Property>
- typename query_result<const Executor&, Property>::type query_helper(
- false_type, const Property& property) const
- {
- return boost::asio::query(executor_, property);
- }
- template <typename Property>
- execution::blocking_t query_helper(true_type, const Property& property) const
- {
- execution::blocking_t result = boost::asio::query(executor_, property);
- return result == execution::blocking.always
- ? execution::blocking.possibly : result;
- }
- Executor executor_;
- implementation_type impl_;
- };
- /** @defgroup make_strand boost::asio::make_strand
- *
- * @brief The boost::asio::make_strand function creates a @ref strand object for
- * an executor or execution context.
- */
- /*@{*/
- /// Create a @ref strand object for an executor.
- template <typename Executor>
- inline strand<Executor> make_strand(const Executor& ex,
- typename constraint<
- is_executor<Executor>::value || execution::is_executor<Executor>::value
- >::type = 0)
- {
- return strand<Executor>(ex);
- }
- /// Create a @ref strand object for an execution context.
- template <typename ExecutionContext>
- inline strand<typename ExecutionContext::executor_type>
- make_strand(ExecutionContext& ctx,
- typename constraint<
- is_convertible<ExecutionContext&, execution_context&>::value
- >::type = 0)
- {
- return strand<typename ExecutionContext::executor_type>(ctx.get_executor());
- }
- /*@}*/
- #if !defined(GENERATING_DOCUMENTATION)
- namespace traits {
- #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
- template <typename Executor>
- struct equality_comparable<strand<Executor> >
- {
- BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
- BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
- };
- #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
- #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
- template <typename Executor, typename Function>
- struct execute_member<strand<Executor>, Function,
- typename enable_if<
- execution::can_execute<const Executor&, Function>::value
- >::type>
- {
- BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
- BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
- typedef void result_type;
- };
- #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
- #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
- template <typename Executor, typename Property>
- struct query_member<strand<Executor>, Property,
- typename enable_if<
- can_query<const Executor&, Property>::value
- >::type>
- {
- BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
- BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
- (is_nothrow_query<Executor, Property>::value));
- typedef typename conditional<
- is_convertible<Property, execution::blocking_t>::value,
- execution::blocking_t, typename query_result<Executor, Property>::type
- >::type result_type;
- };
- #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
- #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
- template <typename Executor, typename Property>
- struct require_member<strand<Executor>, Property,
- typename enable_if<
- can_require<const Executor&, Property>::value
- && !is_convertible<Property, execution::blocking_t::always_t>::value
- >::type>
- {
- BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
- BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
- (is_nothrow_require<Executor, Property>::value));
- typedef strand<typename decay<
- typename require_result<Executor, Property>::type
- >::type> result_type;
- };
- #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
- #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
- template <typename Executor, typename Property>
- struct prefer_member<strand<Executor>, Property,
- typename enable_if<
- can_prefer<const Executor&, Property>::value
- && !is_convertible<Property, execution::blocking_t::always_t>::value
- >::type>
- {
- BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
- BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
- (is_nothrow_prefer<Executor, Property>::value));
- typedef strand<typename decay<
- typename prefer_result<Executor, Property>::type
- >::type> result_type;
- };
- #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
- } // namespace traits
- #endif // !defined(GENERATING_DOCUMENTATION)
- } // namespace asio
- } // namespace boost
- #include <boost/asio/detail/pop_options.hpp>
- // If both io_context.hpp and strand.hpp have been included, automatically
- // include the header file needed for the io_context::strand class.
- #if !defined(BOOST_ASIO_NO_EXTENSIONS)
- # if defined(BOOST_ASIO_IO_CONTEXT_HPP)
- # include <boost/asio/io_context_strand.hpp>
- # endif // defined(BOOST_ASIO_IO_CONTEXT_HPP)
- #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
- #endif // BOOST_ASIO_STRAND_HPP
|