boost::beast::websocket关闭后io_context::run()仍阻塞的排查与解决
问题场景与解决:Boost.Asio线程池配合WebSocket流的阻塞问题
场景说明
- 使用线程池并发调用同一个
io_context运行2个WebSocket流,需执行async_read、async_write等IO操作 - 每个WebSocket流使用独立strand,通过额外锁保证
async_read/async_write不会在前置操作完成前执行
原核心代码
io_context context; std::vector<std::thread> pool(std::thread::hardware_concurrency()); ... wss(make_strand(context),ssl); ... wss.async_read(&loop_read_handler); ... for(auto& th:pool) th=std::thread([&]{ try{ start_read_loop();//give work to do to each thread context.run(); }catch(...){} wss.close(...);//closing the websocket stream, expected to cancel all threads context.stop();//with or without it, no change }); for(auto& th:pool) th.join();//hangs here since the other threads did not return from run()
问题现象
调用close(boost::beast::websocket::close_code::normal, ec)关闭流时:
- 当前线程的IO操作会被取消(收到带
boost::beast::websocket::error::closed错误码的空消息) - 其他线程挂起,
context.run()未检测到流关闭仍等待消息 - 单线程池时无此问题,无论从IO操作内外调用
close或context.stop()都无法解决阻塞
修改后代码
io_context context; auto work=make_work_guard(context);//<<<<<<<<<<<<<<<<<<< std::vector<std::thread> pool(std::thread::hardware_concurrency()); ... wss(make_strand(context),ssl);//I keep it because I will add other streams ... for(auto& th:pool) th=std::thread([&]{ try{ context.run(); }catch(...){} //<<<<<<<<<<<<<<<<<<<<<<<<< close_wss_streams_once_each(...);//cancels all threads }); start_async_read_loop();//<<<<<<<<<<<<<<<<<<< work.reset();//<<<<<<<<<<<<<<<<<<<<<<<<< for(auto& th:pool) th.join();
原因分析
- 原代码错误地在每个线程中提交IO操作,导致线程池任务调度异常
- 使用
work_guard可以在IO任务未全部提交完成前,阻止io_context.run()因无待处理任务提前返回 - 统一在线程池初始化完成后启动一次读循环,避免重复提交任务引发的线程阻塞
内容的提问来源于stack exchange,提问作者kmft3kte
相关产品推荐
相关产品推荐

