关于 boost::asio::strand 初始化 socket、stream、resolver、deadline_timer 对象

本文主要是介绍关于 boost::asio::strand 初始化 socket、stream、resolver、deadline_timer 对象,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在 boost::asio 之中默认情况下,大家使用 io_context 来为这些对象初始化传递的执行者,但我需要这里说明。

对于 boost::asio 构造类似 socket 对象必须构造传递 io_context 是个伪命题,boost::asio 对象并非只允许传递 boost::asio::io_context【重点】。
 

它的构造是接收一个 executor 的,这个 executor 不是非必须是 io_context,这个大家必须要了解,但凡仔细看过文档应该都明白才对,但可惜的国内很多人并不愿意多仔细的看看文档,看着那些所谓大牛的 aiso 经验,贴出来的 demo 代码就算是过了。

这样不好。

在 boost::asio 之中,不同的 asio 对象封装所需要构造传递的执行器略微有些限制,但可以确定的是都不允许:

boost::asio::io_context::strand 传递进去执行,对于传递 strand 的正确做法为:

声明:

            typedef boost::asio::io_context::executor_type                  executor_type;
            typedef boost::asio::strand<executor_type>                      strand;

构造:

方法一:

boost::asio::io_context ioc;

strand(ioc.get_executor());

方法二:

boost::asio::io_context ioc;

boost::asio::make_strand(ioc)

把这个构造出来的 strand 传递给 socket、stream 对象的构造函数就可以了。

当然,上面提到了 asio 的构造初始化并非只是 io_context,只要符合 executor 就可以。

比如:

boost::asio::any_io_executor、boost::asio:::any_completion_executor 就没问题,取决于每个不同 asio 对象构造执行器的限制类型。

比如:

如果我们希望 socket 都运行在一个 strand 上面,按照那些所谓大牛,文档都看不仔细的情况下,大概率是让人们构造一个共享的 boost::asio::io_context::strand,然后在 socket 的异步行为回调函数上都 warp 一次。

但我不建议大家这么做,正确的做法是上述形式,构造 strand 的执行器并在构造的时候传递给 socket 即可,这也包括其它的 asio 对象,如 resolver、DNS解析对象。

本人在此处实现了一个封装,用来模拟串化 io_context。

/* https://www.boost.org/doc/libs/1_71_0/libs/beast/example/websocket/client/async/websocket_client_async.cpp */ 
/* https://fossies.org/linux/boost/libs/asio/test/strand.cpp */
namespace poost {namespace asio {class io_context final {public:typedef boost::asio::io_context::executor_type                  executor_type;typedef boost::asio::strand<executor_type>                      strand;typedef boost::asio::io_context::work                           work;public:io_context() noexcept : io_context(ppp::make_shared_object<boost::asio::io_context>()) {}io_context(const std::shared_ptr<boost::asio::io_context>& context) noexcept                                                                             : context_(context) /* context_->get_executor() */, strand_(boost::asio::make_strand(*context)) {}public:strand&                                                         get_strand() const noexcept { return ppp::constantof(strand_); }boost::asio::io_context&                                        get_context() const noexcept { return *context_; }std::shared_ptr<boost::asio::io_context>                        ptr_context() const noexcept { return context_;}executor_type                                                   get_executor() const noexcept { boost::asio::io_context& context = get_context();return context.get_executor(); }std::shared_ptr<ppp::Byte>                                      ptr_buffers() const noexcept {return buffers_;}void                                                            ptr_buffers(const std::shared_ptr<ppp::Byte>& buffers) const noexcept {ppp::constantof(buffers_) = buffers;}public:template <typename LegacyCompletionHandler>                     void                                                            post(LegacyCompletionHandler&& handler) const noexcept { strand& strand = get_strand();boost::asio::post(strand, handler); }template <typename LegacyCompletionHandler>                     void                                                            dispatch(LegacyCompletionHandler&& handler) const noexcept { strand& strand = get_strand();boost::asio::dispatch(strand, handler); }public:void                                                            restart() noexcept { boost::asio::io_context& context = get_context();context.restart(); } void                                                            run() noexcept;          void                                                            run(boost::system::error_code& ec) noexcept { boost::asio::io_context& context = get_context();context.run(ec); }void                                                            stop() noexcept { boost::asio::io_context& context = get_context();context.stop(); }bool                                                            stopped() noexcept { boost::asio::io_context& context = get_context();return context.stopped(); }private:mutable std::shared_ptr<boost::asio::io_context>                context_;mutable strand                                                  strand_;mutable std::shared_ptr<ppp::Byte>                              buffers_;};inline void                                                         io_context::run() noexcept {boost::system::error_code ec; run(ec); boost::asio::detail::throw_error(ec);}}
}

如何在 socket 上面使用它?

std::shared_ptr<poost::asio::io_context> context;

boost::asio::ip::udp::socket socket_(context->get_strand());

是不是很直观跟简单,那么运行效果会是什么样子呢?

看看线程的调用堆栈是会重叠一层 strand 滴:(所以根本不需要额外的 strand 手动处理)

这篇关于关于 boost::asio::strand 初始化 socket、stream、resolver、deadline_timer 对象的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/849822

相关文章

SpringCloud Stream 快速入门实例教程

《SpringCloudStream快速入门实例教程》本文介绍了SpringCloudStream(SCS)组件在分布式系统中的作用,以及如何集成到SpringBoot项目中,通过SCS,可... 目录1.SCS 组件的出现的背景和作用2.SCS 集成srping Boot项目3.Yml 配置4.Sprin

Java通过ServerSocket与Socket实现通信过程

《Java通过ServerSocket与Socket实现通信过程》本文介绍了Java中的ServerSocket和Socket类,详细讲解了它们的构造方法和使用场景,并通过一个简单的通信示例展示了如何... 目录1 ServerSocket2 Socket3 服务器端4 客户端5 运行结果6 设置超时总结1

浅析Python中如何处理Socket超时

《浅析Python中如何处理Socket超时》在网络编程中,Socket是实现网络通信的基础,本文将深入探讨Python中如何处理Socket超时,并提供完整的代码示例和最佳实践,希望对大家有所帮助... 目录开篇引言核心要点逐一深入讲解每个要点1. 设置Socket超时2. 处理超时异常3. 使用sele

sqlserver、mysql、oracle、pgsql、sqlite五大关系数据库的对象名称和转义字符

《sqlserver、mysql、oracle、pgsql、sqlite五大关系数据库的对象名称和转义字符》:本文主要介绍sqlserver、mysql、oracle、pgsql、sqlite五大... 目录一、转义符1.1 oracle1.2 sqlserver1.3 PostgreSQL1.4 SQLi

JavaScript对象转数组的三种方法实现

《JavaScript对象转数组的三种方法实现》本文介绍了在JavaScript中将对象转换为数组的三种实用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友... 目录方法1:使用Object.keys()和Array.map()方法2:使用Object.entr

分析 Java Stream 的 peek使用实践与副作用处理方案

《分析JavaStream的peek使用实践与副作用处理方案》StreamAPI的peek操作是中间操作,用于观察元素但不终止流,其副作用风险包括线程安全、顺序混乱及性能问题,合理使用场景有限... 目录一、peek 操作的本质:有状态的中间操作二、副作用的定义与风险场景1. 并行流下的线程安全问题2. 顺

使用MapStruct实现Java对象映射的示例代码

《使用MapStruct实现Java对象映射的示例代码》本文主要介绍了使用MapStruct实现Java对象映射的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、什么是 MapStruct?二、实战演练:三步集成 MapStruct第一步:添加 Mave

Java中实现对象的拷贝案例讲解

《Java中实现对象的拷贝案例讲解》Java对象拷贝分为浅拷贝(复制值及引用地址)和深拷贝(递归复制所有引用对象),常用方法包括Object.clone()、序列化及JSON转换,需处理循环引用问题,... 目录对象的拷贝简介浅拷贝和深拷贝浅拷贝深拷贝深拷贝和循环引用总结对象的拷贝简介对象的拷贝,把一个

Java Stream流与使用操作指南

《JavaStream流与使用操作指南》Stream不是数据结构,而是一种高级的数据处理工具,允许你以声明式的方式处理数据集合,类似于SQL语句操作数据库,本文给大家介绍JavaStream流与使用... 目录一、什么是stream流二、创建stream流1.单列集合创建stream流2.双列集合创建str

Java Stream 并行流简介、使用与注意事项小结

《JavaStream并行流简介、使用与注意事项小结》Java8并行流基于StreamAPI,利用多核CPU提升计算密集型任务效率,但需注意线程安全、顺序不确定及线程池管理,可通过自定义线程池与C... 目录1. 并行流简介​特点:​2. 并行流的简单使用​示例:并行流的基本使用​3. 配合自定义线程池​示