Boost Cobalt+Asio异常问题:无效主机未按预期抛出异常
Boost Cobalt+Asio解析无效主机时异常未被捕获导致进程终止
问题现象
- 解析有效主机URL时,代码运行正常;
- 解析无效主机URL时,预期异常会被catch块捕获,但实际未进入捕获逻辑,而是输出错误信息并触发SIGABRT终止进程。
相关代码
#include <boost/cobalt.hpp> #include <boost/asio.hpp> #include <boost/asio/ssl.hpp> #include <iostream> #include <string> #include <vector> namespace net = boost::asio; namespace cobalt = boost::cobalt; using executor_type = cobalt::executor; cobalt::task<std::vector<net::ip::tcp::endpoint>> resolve( executor_type executor, std::string const& hostname, std::string const& service ) { auto endpoints = std::vector<net::ip::tcp::endpoint>{}; auto resolver = net::ip::tcp::resolver{executor}; try { auto results = co_await resolver.async_resolve( hostname, service, cobalt::use_op); for (const auto& result : results) endpoints.push_back(result.endpoint()); co_return endpoints; } catch (...) { std::cerr << "Resolve exception\n"; throw; } } cobalt::task<void> main2() { auto executor = co_await cobalt::this_coro::executor; auto endpoints = co_await resolve(executor, "www.googleqqq.com", "https"); // 故意设置无效主机,改为www.google.com可正常运行 // 打印解析后的端点 for (const auto& endpoint : endpoints) std::cerr << endpoint << std::endl; co_return; } int main() { try { net::io_context ctx; cobalt::spawn(ctx, main2(), net::detached); ctx.run(); } catch (...) { std::cerr << "Uncaught exception\n"; } return 0; }
CMakeLists.txt配置
注:为避免强制用户在系统安装Boost,使用了FetchContent,首次编译会耗时几分钟。
注:需要提前安装OpenSSL。
cmake_minimum_required(VERSION 3.30) project(async_resolve_exception_issue) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) include(FetchContent) # OpenSSL find_package(OpenSSL REQUIRED) # Boost FetchContent_Declare( boost GIT_REPOSITORY https://github.com/boostorg/boost.git GIT_TAG boost-1.85.0 GIT_SHALLOW TRUE GIT_PROGRESS TRUE OVERRIDE_FIND_PACKAGE ) FetchContent_MakeAvailable(boost) find_package(Boost 1.85 REQUIRED COMPONENTS system) add_executable(${PROJECT_NAME} ${PROJECT_NAME}.cpp ) target_link_libraries(${PROJECT_NAME} PUBLIC Boost::beast Boost::cobalt OpenSSL::SSL OpenSSL::Crypto )
执行命令
build/async_resolve_exception_issue
错误信息
libc++abi: terminating due to uncaught exception of type boost::detail::with_throw_location<boost::system::system_error>: Host not found (authoritative) [asio.netdb:1]
运行环境
- MacOS Sonoma(14.6)
- cmake 3.30.2
- clang 18.1.8
问题原因及解决方法
问题根源在于使用cobalt::spawn时传入了net::detached参数:
- 当协程以
detached模式运行时,协程内部未捕获的异常会直接调用std::terminate()终止进程,无法传递到main函数的catch块中。
解决方法1:捕获协程内的异常
在main2协程中直接捕获resolve抛出的异常,避免异常扩散到detached协程外:
cobalt::task<void> main2() { auto executor = co_await cobalt::this_coro::executor; try { auto endpoints = co_await resolve(executor, "www.googleqqq.com", "https"); for (const auto& endpoint : endpoints) std::cerr << endpoint << std::endl; } catch(const std::exception& e) { std::cerr << "解析失败:" << e.what() << std::endl; // 可根据需求处理异常,无需重新抛出 } co_return; }
解决方法2:避免使用detached模式,获取协程结果
修改main函数,不使用detached,而是通过task.get()获取协程结果,此时异常会被传递到main的catch块:
int main() { try { net::io_context ctx; auto coro_task = cobalt::spawn(ctx, main2()); ctx.run(); coro_task.get(); // 触发协程中未捕获的异常 } catch (const std::exception& e) { std::cerr << "捕获到异常:" << e.what() << std::endl; } return 0; }
解决方法3:自定义detached协程的异常处理
如果必须使用detached模式,可以通过cobalt::spawn的重载版本传入异常处理函数:
void handle_coro_exception(std::exception_ptr e) { try { if (e) std::rethrow_exception(e); } catch(const std::exception& ex) { std::cerr << "协程异常处理:" << ex.what() << std::endl; } } int main() { net::io_context ctx; cobalt::spawn(ctx, main2(), cobalt::detached, handle_coro_exception); ctx.run(); return 0; }
内容的提问来源于stack exchange,提问作者user5406764
相关产品推荐
相关产品推荐

