Boost.Asio Daytime服务器用std::async遇问题及疑问求助
Boost.Asio Daytime 服务器改编相关问题解答
背景
我在学习Boost.Asio(版本1.84,基于C++20,运行环境Ubuntu 23.04),改编了官方的Daytime服务器示例。为模拟耗时任务,我让make_daytime_string()睡眠5秒,用std::async异步执行这个任务,之后在std::async的任务末尾通过boost::asio::post调用async_write,确保它和其他完成处理程序在同一线程执行。
问题与解答
问题1:是否必须用post?直接在std::async里调用async_write行不行?二者有啥区别?
- 直接调用是允许的,但不推荐,不符合Asio的线程安全规范:
- 用
boost::asio::post的好处:- 把
async_write的启动逻辑提交到Asio的io_context线程执行,严格遵循Asio的IO对象线程安全规则——IO对象(比如socket)的操作应该在同一个strand或io_context线程中发起,避免多线程操作引发竞态问题。 - 所有IO相关的完成处理程序都在统一的线程上下文执行,不用额外处理跨线程同步的问题。
缺点就是多了一次任务调度的微小开销,基本可以忽略。
- 把
- 直接在
std::async任务里调用的问题:std::async的线程是标准库管理的,不属于Asio的io_context线程池。直接在这线程里调用async_write,相当于在非Asio管理的线程操作IO对象,可能触发线程安全风险;而且后续的完成处理程序执行线程可能和其他Asio逻辑不在同一上下文,增加代码的复杂度。
- 用
问题2:tcp_connection析构函数不触发,客户端收不到boost::asio::error::eof,只有终止服务器时客户端才关闭
问题根源
全局的std::future持有了tcp_connection的shared_ptr,导致对象的引用计数一直没法降到0,所以析构函数不会被调用,socket也不会主动关闭,客户端自然收不到eof错误。
解决方法
用移动语义转移shared_ptr的所有权,让std::future不再持有这个对象的持久引用。异步任务完成后,shared_ptr的引用计数会正常递减,对象得以析构,socket正常关闭,客户端就能收到eof信号了。
内容的提问来源于stack exchange,提问作者SoulfreezerXP
相关产品推荐
相关产品推荐

