You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Boost.Asio上下文内等待std::future完成?

实现WaitForFutureAsync的核心要求与代码方案

核心功能需求

要让std::future能在Asio的io_context中以类似定时器的异步方式等待,WaitForFutureAsync必须满足以下要求:

  • 异步启动后立即返回,不阻塞调用线程
  • 当std::future就绪(完成/异常)时,回调函数必须在io_context::run()的线程中执行
  • 与Asio的异步模型对齐,通过error_code传递执行结果(成功、异常、取消等状态)
  • 兼容C17标准,不能使用C20及以上特性

实现思路

C++17的std::future没有原生异步通知机制,只能通过同步等待感知就绪状态。因此我们需要:

  1. 启动后台线程,同步等待std::future就绪
  2. 当future就绪后,通过Asio的post接口将回调投递到io_context的执行队列
  3. 捕获future可能抛出的异常,转化为符合Asio规范的error_code

完整代码实现

#include <asio.hpp>
#include <future>
#include <thread>
#include <functional>
#include <iostream>

void WaitForFutureAsync(asio::io_context& ctx, std::future<int> f, std::function<void(const std::error_code&)> callback) {
    // 启动后台线程等待future就绪
    std::thread([ctx_ref = std::ref(ctx), 
                 f = std::move(f), 
                 callback = std::move(callback)]() mutable {
        std::error_code ec;
        try {
            // 同步等待future完成
            f.wait();
            // 获取结果,捕获可能的异常
            (void)f.get();
            ec = asio::error::success;
        } catch (const std::future_error&) {
            // 处理future被取消/异常的情况
            ec = asio::error::operation_aborted;
        } catch (const std::exception&) {
            // 处理用户自定义异常
            ec = asio::error::fault;
        } catch (...) {
            // 处理未知异常
            ec = asio::error::unknown;
        }

        // 将回调投递到io_context线程执行
        asio::post(ctx_ref.get_executor(), 
                   [callback = std::move(callback), ec]() {
                       callback(ec);
                   });
    }).detach(); // 分离线程,让其自行完成生命周期
}

// 测试用户提供的伪代码
void AddFutureToIoContext(std::future<int> f) {
    asio::io_context ctx;
    // 使用work_guard防止io_context在回调执行前退出
    auto work_guard = asio::make_work_guard(ctx);

    WaitForFutureAsync(ctx, std::move(f), [&work_guard](const std::error_code& error){
        std::cout << "The future has come";
        if (error) {
            std::cout << " with error: " << error.message() << std::endl;
        } else {
            std::cout << " successfully." << std::endl;
        }
        // 释放work_guard,允许io_context退出
        work_guard.reset();
    });

    ctx.run();
}

// 测试入口
int main() {
    std::promise<int> p;
    auto future = p.get_future();

    // 模拟异步任务
    std::thread([p = std::move(p)]() mutable {
        std::this_thread::sleep_for(std::chrono::seconds(2));
        p.set_value(42); // 标记future完成
        // 若要测试异常情况,可替换为:p.set_exception(std::make_exception_ptr(std::runtime_error("test error")));
    }).detach();

    AddFutureToIoContext(std::move(future));
    return 0;
}

关键细节说明

  • 移动语义:std::future不可拷贝,必须通过std::move传递,确保资源所有权正确转移
  • Work Guard:必须使用asio::make_work_guard,否则io_context::run()会在没有待处理任务时立即退出,无法等待回调执行
  • 线程安全:Asio的post操作是线程安全的,后台线程可以安全地将回调投递到io_context
  • 异常转化:将future的各种异常情况映射到Asio标准error_code,符合Asio的错误处理范式
  • 线程生命周期:后台线程使用detach(),无需主线程等待,其唯一职责是等待future并投递回调

内容的提问来源于stack exchange,提问作者Anders Brodin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:13:14