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

相关文章

Java数组初始化的五种方式

《Java数组初始化的五种方式》数组是Java中最基础且常用的数据结构之一,其初始化方式多样且各具特点,本文详细讲解Java数组初始化的五种方式,分析其适用场景、优劣势对比及注意事项,帮助避免常见陷阱... 目录1. 静态初始化:简洁但固定代码示例核心特点适用场景注意事项2. 动态初始化:灵活但需手动管理代

QT进行CSV文件初始化与读写操作

《QT进行CSV文件初始化与读写操作》这篇文章主要为大家详细介绍了在QT环境中如何进行CSV文件的初始化、写入和读取操作,本文为大家整理了相关的操作的多种方法,希望对大家有所帮助... 目录前言一、CSV文件初始化二、CSV写入三、CSV读取四、QT 逐行读取csv文件五、Qt如何将数据保存成CSV文件前言

Python中判断对象是否为空的方法

《Python中判断对象是否为空的方法》在Python开发中,判断对象是否为“空”是高频操作,但看似简单的需求却暗藏玄机,从None到空容器,从零值到自定义对象的“假值”状态,不同场景下的“空”需要精... 目录一、python中的“空”值体系二、精准判定方法对比三、常见误区解析四、进阶处理技巧五、性能优化

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

Spring组件初始化扩展点BeanPostProcessor的作用详解

《Spring组件初始化扩展点BeanPostProcessor的作用详解》本文通过实战案例和常见应用场景详细介绍了BeanPostProcessor的使用,并强调了其在Spring扩展中的重要性,感... 目录一、概述二、BeanPostProcessor的作用三、核心方法解析1、postProcessB

C#原型模式之如何通过克隆对象来优化创建过程

《C#原型模式之如何通过克隆对象来优化创建过程》原型模式是一种创建型设计模式,通过克隆现有对象来创建新对象,避免重复的创建成本和复杂的初始化过程,它适用于对象创建过程复杂、需要大量相似对象或避免重复初... 目录什么是原型模式?原型模式的工作原理C#中如何实现原型模式?1. 定义原型接口2. 实现原型接口3

Java实现将byte[]转换为File对象

《Java实现将byte[]转换为File对象》这篇文章将通过一个简单的例子为大家演示Java如何实现byte[]转换为File对象,并将其上传到外部服务器,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言1. 问题背景2. 环境准备3. 实现步骤3.1 从 URL 获取图片字节数据3.2 将字节数组

Javascript访问Promise对象返回值的操作方法

《Javascript访问Promise对象返回值的操作方法》这篇文章介绍了如何在JavaScript中使用Promise对象来处理异步操作,通过使用fetch()方法和Promise对象,我们可以从... 目录在Javascript中,什么是Promise1- then() 链式操作2- 在之后的代码中使