I have a function that returns boost::asio::awaitable
. What is the idiomatic way to convert this awaitable to std::future
?
Before we get into the answer, be warned:
You should not, under any circumstance, get()
or wait()
a future to a boost::asio::awaitable
from the same thread as the executor that is running the coroutine.
That being said.
That third parameter to co_spawn()
, the one almost every example blindly sets to the magic detached
constant? Its role is to tell boost::asio
what to do once the coroutine has finished. detached
simply means "do nothing". So the canonical way to fulfil a future from an awaitable<>
should be via that mechanism.
Thankfully, asio already provides the use_future
completion token. Pass that as the third parameter to co_spawn()
and it will return a std::future<>
of the matching return type.
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);
Here's a full example:
#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;
}
Obviously, this means you need access to the io context in order to produce the future.
If you are already inside of a coroutine and have no access to the io_context, then you have to create the future before calling the subroutine, and co_await
its result before fullfilling the future. std::promise<>
is perfectly suited for that task:
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;
}
If you are not within a coroutine, and do not have access to an io_context, then you can't invoke the coroutine in the first place. So either of these approaches should have you covered.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With