【问题标题】:boost::asio::co_spawn does not propagate exceptionboost::asio::co_spawn 不传播异常
【发布时间】:2021-09-03 14:08:48
【问题描述】:

我正在涉足与 boost::asio 相关的协程,但我对异常处理感到困惑。从 examples in 文档来看,看起来任何“失败”error_code 都变成了异常 - 所以我希望任何抛出的异常也会传播回co_spawn 打电话。但情况似乎并非如此:

#define BOOST_ASIO_HAS_CO_AWAIT
#define BOOST_ASIO_HAS_STD_COROUTINE

#include <iostream>

#include <boost/asio/awaitable.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/executor_work_guard.hpp>

namespace this_coro = boost::asio::this_coro;

boost::asio::awaitable<void> async_op()
{
    std::cout << "About to throw" << std::endl;
    throw std::runtime_error{"Bang!"};
}

int main()
{
    auto ctx = boost::asio::io_context{};
    auto guard = boost::asio::make_work_guard(ctx.get_executor());

    boost::asio::co_spawn(ctx, async_op, boost::asio::detached);

    ctx.run();
}

如果在调试器中运行,您可以看到异常被抛出,但它似乎只是挂起。暂停调试器表明ctx.run() 正在等待新的工作(由于executor_work_guard)。所以看起来 boost::asio 内部的某些东西默默地吞下了异常。

作为一个实验,我将异步操作切换为使用 boost::asio 库调用:

boost::asio::awaitable<void> async_op()
{
    auto executor = co_await this_coro::executor;
    auto socket = boost::asio::ip::tcp::socket{executor};

    std::cout << "Starting resolve" << std::endl;
    auto resolver = boost::asio::ip::tcp::resolver{executor};
    const auto endpoints = co_await resolver.async_resolve("localhost",
                                                           "4444",
                                                           boost::asio::use_awaitable);



    std::cout << "Starting connect (num endpoints: " << endpoints.size() << ")" << std::endl;
    co_await boost::asio::async_connect(socket, endpoints, boost::asio::use_awaitable);
    std::cout << "Exited" << std::endl;
}

我没有在端口 4444 上运行服务器,所以这应该会立即失败 - 它确实会以静默方式运行。暂停调试器表明它卡在 epoll 中等待某些东西(我在 Linux 上)。

async_connect CompletionToken 交换为boost::asio::redirect_error 表明操作失败:

co_await boost::asio::async_connect(socket,
                                    endpoints, 
                                    boost::asio::redirect_error(boost::asio::use_awaitable, ec));
std::cout << "Exited: " << ec.message() << std::endl;

产量:

Starting resolve
Starting connect (num endpoints: 1)
Exited: Connection refused

那么我如何传播异常,并从 error_codes 中创建它们,而不是 boost::asio 中的协程?

【问题讨论】:

    标签: c++ exception boost coroutine


    【解决方案1】:

    boost::asio::co_spawn 创建一个separate thread。这意味着异常不会传播。您可以在此处阅读更多相关信息:

    但是co_spawn 支持带有签名void(std::exception_ptr, R) 的完成处理程序。在您的示例中,您使用了boost::asio::detached,这意味着忽略了完成结果。传播它只是write a custom handler

    【讨论】:

    • 我想知道我是如何错过co_spawnCompletionToken 回调签名的,但这是因为我正在查看没有示例的v1.71 文档。非常感谢,现在可以正常使用了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-21
    • 2015-06-05
    • 2015-01-15
    • 1970-01-01
    • 2012-03-07
    • 1970-01-01
    相关资源
    最近更新 更多