关于 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

相关文章

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. 配合自定义线程池​示

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱

Java中的stream流分组示例详解

《Java中的stream流分组示例详解》Java8StreamAPI以函数式风格处理集合数据,支持分组、统计等操作,可按单/多字段分组,使用String、Map.Entry或Java16record... 目录什么是stream流1、根据某个字段分组2、按多个字段分组(组合分组)1、方法一:使用 Stri

使用Java读取本地文件并转换为MultipartFile对象的方法

《使用Java读取本地文件并转换为MultipartFile对象的方法》在许多JavaWeb应用中,我们经常会遇到将本地文件上传至服务器或其他系统的需求,在这种场景下,MultipartFile对象非... 目录1. 基本需求2. 自定义 MultipartFile 类3. 实现代码4. 代码解析5. 自定

Java Stream流以及常用方法操作实例

《JavaStream流以及常用方法操作实例》Stream是对Java中集合的一种增强方式,使用它可以将集合的处理过程变得更加简洁、高效和易读,:本文主要介绍JavaStream流以及常用方法... 目录一、Stream流是什么?二、stream的操作2.1、stream流创建2.2、stream的使用2.