【问题标题】:How to convert boost::asio::awaitable to std::future?如何将 boost::asio::awaitable 转换为 std::future?
【发布时间】:2021-06-09 16:56:26
【问题描述】:

我有一个返回 boost::asio::awaitable 的函数。将这个等待转换为std::future 的惯用方法是什么?

【问题讨论】:

  • @Frank 以其简洁明了的回答有可能启发很多人。您愿意将其发布为答案吗?
  • @sehe 我不知道“图书馆有一个按钮”是否会成为一个“绝妙”的答案,但经过反思,你是对的,这有可能解除对很多人。感谢您的提示。我删除了之前的评论,因为如果这成为常用的问答,我觉得答案前言中的警告很重要。

标签: c++ boost-asio


【解决方案1】:

在我们得到答案之前,请注意:

在任何情况下,您都不应该将get()wait() 与运行协程的执行程序来自同一线程的boost::asio::awaitable 的未来。

就是这么说的。

co_spawn() 的第三个参数,几乎每个示例都盲目地设置为神奇的detached 常量?它的作用是告诉boost::asio 协程完成后要做什么。 detached 仅表示“什么也不做”。因此,从awaitable<> 实现未来的规范方法应该是通过该机制。

谢天谢地,asio 已经提供了use_future 完成令牌。将其作为第三个参数传递给co_spawn(),它将返回匹配返回类型的std::future<>

boost::asio::awaitable<void> foo();
boost::asio::awaitable<int> bar();

std::future<void> foo_fut = boost::asio:co_spawn(io_context, foo(), boost::asio::use_future);
std::future<int> bar_fut = boost::asio:co_spawn(io_context, bar(), boost::asio::use_future);

这是一个完整的例子:

#include <boost/asio/io_context.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/use_future.hpp>

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

using boost::asio::awaitable;
using boost::asio::co_spawn;
using boost::asio::io_context;
using boost::asio::use_future;

awaitable<void> foo() {
  // Simulate foo taking a while to run
  std::this_thread::sleep_for(std::chrono::seconds(1));
  std::cout << "foo\n";
  co_return;
}

int main() {
  try {
    io_context context;
    std::future<void> fut = co_spawn(context, foo(), use_future);

    std::thread waiter([fut=std::move(fut)](){
        std::cout << "AAA\n";
        fut.wait();
        std::cout << "BBB\n";
    });

    context.run();

    waiter.join();
  
  } catch(const std::exception &ex) {
    std::cerr << ex.what() << std::endl;
  }
  return 0;
}

显然,这意味着您需要访问 io 上下文才能产生未来。

如果您已经在协程内部并且无法访问 io_context,那么您必须在调用子例程之前创建未来,并在填充未来之前co_await 其结果。 std::promise&lt;&gt; 非常适合该任务:

awaitable<void> sub_foo() {
  co_return;
}

awaitable<void> foo() {
  std::promise<void> prom;
  auto fut = prom.get_future();
  // send the future somewhere
  
  co_await sub_foo();

  prom.set_value();

  co_return;
}

如果您不在协程中,并且无权访问 io_context,那么您一开始就无法调用协程。所以这两种方法中的任何一种都应该能满足您的需求。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-25
    • 1970-01-01
    相关资源
    最近更新 更多