Boost.Asio 提供了建议的标准执行器的完整实现,如 P0443r13、P1348r0 和 P1393r0 中所述。
与 Networking TS 模型下的执行器一样,标准执行器表示关于一段代码应该如何、何时以及在何处执行的策略。大多数现有代码应该可以继续工作,几乎不需要或不需要更改。
io_context::executor_type
、thread_pool::executor_type
、system_executor
和 strand
执行器满足建议的标准执行器的要求。为了兼容性,这些类也满足 Networking TS 模型对执行器的要求。
所有 I/O 对象,例如 ip::tcp::socket
、异步操作和实用程序(包括 dispatch
、post
、defer
、get_associated_executor
、bind_executor
、make_work_guard
、spawn
、co_spawn
、async_compose
、use_future
等),都可以与建议的标准执行器和 Networking TS 执行器互操作。Boost.Asio 的实现在编译时确定特定执行器符合哪个模型;如果检测到两者,则优先使用建议的标准执行器模型。
可以通过定义 BOOST_ASIO_NO_TS_EXECUTORS
来禁用对现有 Networking TS 模型的执行器的支持。
any_io_executor
类型别名是所有 I/O 对象的默认运行时多态执行器。此类型别名指向 execution::any_executor<>
模板,其中指定了一组可支持的属性以用于 I/O。
此新名称可能会破坏直接使用旧的多态包装器 executor
的现有代码。如果为了向后兼容性需要,可以定义 BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT
,这会将 any_io_executor
类型别名更改为指向 executor
多态包装器。
标准执行器属性将以前对执行器的硬性要求(例如工作计数,或区分 post
、dispatch
和 defer
的能力)变成了可选的功能。通过这种放宽,对 I/O 执行器的最低要求是
executor
概念。execution::context
属性,结果为 execution_context&
或对从 execution_context
派生的类的引用。execute
操作至少具有 execution::blocking.never
语义。以下示例显示了一个最小的 I/O 执行器。假设队列提交操作在其他地方实现
queue_t queue_create(); template <typename F> void queue_submit(queue_t q, F f);
执行器可以定义如下
struct minimal_io_executor { boost::asio::execution_context* context_; queue_t queue_; bool operator==(const minimal_io_executor& other) const noexcept { return context_ == other.context_ && queue_ == other.queue_; } bool operator!=(const minimal_io_executor& other) const noexcept { return !(*this == other); } boost::asio::execution_context& query( boost::asio::execution::context_t) const noexcept { return *context_; } static constexpr boost::asio::execution::blocking_t::never_t query( boost::asio::execution::blocking_t) noexcept { // This executor always has blocking.never semantics. return boost::asio::execution::blocking.never; } template <class F> void execute(F f) const { queue_submit(queue_, std::move(f)); } };
可以按如下方式创建此执行器
boost::asio::execution_context context; queue_t queue = queue_create(); minimal_io_executor executor{&context, queue};
然后与 I/O 对象一起使用
boost::asio::ip::tcp::acceptor acceptor(executor);
或分配到 any_io_executor
多态包装器中
boost::asio::any_io_executor poly_executor = executor;
较旧的 C++ 标准和编译器需要一些帮助来确定执行器实现是否符合 executor
概念和类型要求。这是通过特征的专门化来实现的。以下代码显示了上述 minimal_io_executor
示例的这些特征的专门化
namespace boost { namespace asio { namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) template <typename F> struct execute_member<minimal_io_executor, F> { static constexpr bool is_valid = true; static constexpr bool is_noexcept = true; typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) template <> struct equality_comparable<minimal_io_executor> { static constexpr bool is_valid = true; static constexpr bool is_noexcept = true; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) template <> struct query_member<minimal_io_executor, boost::asio::execution::context_t> { static constexpr bool is_valid = true; static constexpr bool is_noexcept = true; typedef boost::asio::execution_context& result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) template <typename Property> struct query_static_constexpr_member<minimal_io_executor, Property, typename enable_if< std::is_convertible<Property, boost::asio::execution::blocking_t>::value >::type> { static constexpr bool is_valid = true; static constexpr bool is_noexcept = true; typedef boost::asio::execution::blocking_t::never_t result_type; static constexpr result_type value() noexcept { return result_type(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) } // namespace traits } } // namespace boost::asio
Boost.Asio 使用一组广泛的特征来在较旧的 C++ 标准上实现所有建议的标准执行器功能。这些特征可以在 boost/asio/traits
include 目录下找到。