Boost协程执行async_write后无法恢复,如何检测状态并重启?
Boost.Coroutine异常状态检测与自动重启方案
核心问题分析
你的代码存在几个潜在问题,也是导致协程静默挂起/退出的原因:
- 未处理异步操作的错误码,当socket写入或定时器等待出错时,协程可能进入异常路径或静默退出
- 未捕获协程内的异常,一旦出现未处理异常,协程会直接销毁,且不会有任何提示
io_service.run()在无任务时会返回,未调用reset()导致后续无法处理新任务
解决方法:异常捕获+自动重启
通过给协程添加异常捕获逻辑,并在协程结束时自动重启,即可解决随机挂起问题。同时处理异步操作的错误码,避免静默失败。
修改后的完整代码
#include <iostream> #include <boost/asio.hpp> #include <boost/asio/spawn.hpp> #include <boost/system/error_code.hpp> #include <boost/chrono.hpp> boost::asio::io_service io_service; boost::asio::ip::tcp::socket* socket_; boost::asio::steady_timer timer{io_service}; // 假设buffer是已定义的全局缓冲区,比如char buffer[1024]; void write_to_socket(boost::asio::yield_context yield_context) { try { while(true){ boost::system::error_code ec; // 执行异步写入 socket_->async_write_some(boost::asio::buffer(buffer), yield_context[ec]); if (ec) { std::cerr << "写入错误: " << ec.message() << std::endl; break; // 退出循环,触发协程重启 } std::cout << "Done, now sleep for 10 ms" << std::endl; // 定时器等待 timer.expires_from_now(boost::chrono::milliseconds(10)); timer.async_wait(yield_context[ec]); if (ec) { std::cerr << "定时器等待错误: " << ec.message() << std::endl; break; } } } catch (const std::exception& e) { std::cerr << "协程异常: " << e.what() << std::endl; } catch (...) { std::cerr << "协程未知异常" << std::endl; } // 协程结束后自动重启 boost::asio::spawn(io_service, &write_to_socket); } int main () { // 此处需补充socket初始化与连接逻辑 // socket_ = new boost::asio::ip::tcp::socket(io_service); // boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string("127.0.0.1"), 8080); // socket_->connect(ep); // 启动第一个协程 boost::asio::spawn(io_service, &write_to_socket); while(true){ io_service.run(); io_service.reset(); // 重置io_service,确保下次run能处理新任务 } }
关键细节说明
- 异常捕获:在协程函数内添加
try-catch块,捕获所有可能的异常,避免协程因未处理异常静默销毁。 - 错误码处理:每个异步操作后检查错误码,当出现错误时主动退出循环,触发协程重启。
- 自动重启:在协程函数末尾重新调用
boost::asio::spawn,无论协程是正常退出还是异常退出,都会自动生成新的协程。 - io_service重置:
io_service.run()在无任务时会返回,调用reset()可以重置内部状态,确保后续run()能处理新的协程任务。
协程状态检测(可选)
如果需要主动检测协程是否活跃,可以通过yield_context获取coroutine_handle:
auto handle = yield_context.native_handle(); if (!handle.is_valid()) { // 协程已销毁,执行重启逻辑 boost::asio::spawn(io_service, &write_to_socket); }
但实际场景中,自动重启的方式更简洁可靠,无需主动轮询检测。
内容的提问来源于stack exchange,提问作者NamasriAditya
相关产品推荐
相关产品推荐

