使用use_future的Boost Asio异步连接偶发段错误问题排查
ASIO结合use_future实现异步Socket连接时偶发段错误问题排查
我在使用asio库结合use_future实现Socket异步连接时,代码90%的时间能正常运行,但偶尔会出现段错误。排查后发现代码会打印checkpoint 2、3,但不会打印checkpoint 4。
lldb调试得到以下信息:
Process 63910 stopped * thread #4, stop reason = EXC_BAD_ACCESS (code=2, address=0x100072e08) frame #0: 0x000000010002648c XYZ`std::__1::enable_if<is_error_code_enum<asio::error::basic_errors>::value, std::__1::error_code&>::type std::__1::error_code::operator=<asio::error::basic_errors>(this=0x0000000100072e08, __e=operation_aborted) at system_error:349:20 346 error_code& 347 >::type 348 operator=(_Ep __e) _NOEXCEPT -> 349 {*this = make_error_code(__e); return *this;} 350 351 _LIBCPP_INLINE_VISIBILITY 352 void clear() _NOEXCEPT Target 0: (XYZ) stopped.
相关代码如下:
struct Peer { std::string address; uint16_t port; }; class bar { private: std::shared_ptr<asio::ip::tcp::endpoint> endpoint; std::shared_ptr<asio::io_context> context; std::shared_ptr<asio::ip::tcp::socket> socket; public: bool foo(Peer peer); }; bool bar::foo(Peer peer) { endpoint = std::move(std::make_shared<asio::ip::tcp::endpoint>(asio::ip::make_address(peer.address), peer.port)); context = std::move(std::make_shared<asio::io_context>()); socket = std::move(std::make_shared<asio::ip::tcp::socket>(*context)); std::chrono::milliseconds span(100); std::chrono::milliseconds zero_s(0); std::cout << "checkpoint 2" << std::endl; std::future<void> connect_status = socket->async_connect(*endpoint, asio::use_future); context->run_for(span); std::cout << "checkpoit 3" << std::endl; if (connect_status.wait_for(zero_s) == std::future_status::timeout) return false; std::cout << "checkpoint 4" << std::endl; connect_status.get(); }
问题原因及修复方案
经排查,问题出在对象析构顺序与构造顺序相反。当重复调用foo方法时,移动赋值操作会先销毁旧的context,而此时旧的socket还未被销毁,socket的析构函数执行时依赖的context已经超出作用域,从而引发段错误。
修正后的代码如下:
socket.reset(); context.reset(); endpoint.reset(); endpoint = std::make_shared<asio::ip::tcp::endpoint>(asio::ip::make_address(peer.address), peer.port); context = std::make_shared<asio::io_context>(); socket = std::make_shared<asio::ip::tcp::socket>(*context);
内容的提问来源于stack exchange,提问作者ILutRf7
相关产品推荐
相关产品推荐

