首页 > 解决方案 > 使用协程时 boost::asio 超时的最佳实践

问题描述

下面的连接尝试创建(在我的网络配置上)2 分钟的延迟,因为目标不存在并且地址与我的机器位于不同的子网上。所以我添加了超时逻辑以将尝试限制为 5 秒:

#define BOOST_ASIO_HAS_CO_AWAIT
#define BOOST_ASIO_HAS_STD_COROUTINE

#include <iostream>
#include <chrono>
#include <thread>

#include <boost/asio/awaitable.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/address_v4.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/redirect_error.hpp>

namespace this_coro = boost::asio::this_coro;
using namespace std::chrono_literals;

boost::asio::awaitable<void> fail_to_connect()
{
    auto executor = co_await this_coro::executor;
    auto socket = boost::asio::ip::tcp::socket{executor};
    auto ep = boost::asio::ip::tcp::endpoint{
                    boost::asio::ip::make_address_v4("192.168.1.52"),
                    80};

    auto timer = boost::asio::steady_timer{executor};
    timer.expires_after(5s);
    boost::asio::co_spawn(
        executor,
        [&]() -> boost::asio::awaitable<void> {
            auto ec = boost::system::error_code{};
            co_await timer.async_wait(boost::asio::redirect_error(boost::asio::use_awaitable, ec));
            std::cout << "Thread ID: " << std::this_thread::get_id()
                      << " Timer: " << ec.message() << std::endl;
            if (!ec) {
                socket.close();
            }
        },
        boost::asio::detached
    );

    std::cout << "Thread ID: " << std::this_thread::get_id()
              << " Starting connection" << std::endl;
    co_await boost::asio::async_connect(socket,
                                        std::array{std::move(ep)},
                                        boost::asio::use_awaitable);
    timer.cancel();
}

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

    auto exception_handler = [&](auto e_ptr) {
        if (e_ptr) {
            std::rethrow_exception(e_ptr);
        }
    };

    boost::asio::co_spawn(ctx, fail_to_connect, std::move(exception_handler));
    ctx.run();
}

这按预期工作。从线程 ID 中可以看出,在两个协程之间使用相同的执行上下文意味着我也不会同时访问套接字。

14:58:41: Starting /home/cmannett85/workspace/build-scratch-Desktop-Debug/scratch ...
Thread ID: 140171855615808 Starting connection
Thread ID: 140171855615808 Timer: Success
terminate called after throwing an instance of 'boost::system::system_error'
  what():  Operation canceled
14:58:46: The program has unexpectedly finished.

然而,这感觉很笨拙,尤其是与非协程回调样式相比。使用协程是否有更好的超时方法?我正在努力寻找例子。

标签: c++boosttimeoutasio

解决方案


推荐阅读