如何将boost::asio::awaitable转换成std::future?
How to convert boost::asio::awaitable to std::future?
我有一个函数 returns boost::asio::awaitable
。将此等待对象转换为 std::future
的惯用方法是什么?
在我们进入答案之前,请注意:
在任何情况下,您都不应该 get()
或 wait()
从与 运行 协程的执行者相同的线程到 boost::asio::awaitable
的未来。
话虽这么说。
co_spawn()
的第三个参数,几乎每个示例都盲目地设置为神奇的 detached
常量?它的作用是告诉 boost::asio
协程完成后要做什么。 detached
简单的意思是“什么都不做”。因此,从 awaitable<>
实现未来的规范方式应该是通过该机制。
幸运的是,asio 已经提供了 use_future
完成标记。将其作为第三个参数传递给 co_spawn()
,它将 return 匹配 return 类型的 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<>
非常适合这项任务:
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,那么您首先无法调用协程。因此,这些方法中的任何一种都应该满足您的要求。
我有一个函数 returns boost::asio::awaitable
。将此等待对象转换为 std::future
的惯用方法是什么?
在我们进入答案之前,请注意:
在任何情况下,您都不应该 get()
或 wait()
从与 运行 协程的执行者相同的线程到 boost::asio::awaitable
的未来。
话虽这么说。
co_spawn()
的第三个参数,几乎每个示例都盲目地设置为神奇的 detached
常量?它的作用是告诉 boost::asio
协程完成后要做什么。 detached
简单的意思是“什么都不做”。因此,从 awaitable<>
实现未来的规范方式应该是通过该机制。
幸运的是,asio 已经提供了 use_future
完成标记。将其作为第三个参数传递给 co_spawn()
,它将 return 匹配 return 类型的 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<>
非常适合这项任务:
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,那么您首先无法调用协程。因此,这些方法中的任何一种都应该满足您的要求。