C++ Coroutines Advanced: Converting std:future to asio:awaitable

53 xialeistudio 24 7/15/2025, 1:50:12 AM ddhigh.com ↗

Comments (24)

mgaunard · 5h ago
So the solution is to have a thread waiting on the future. Technically you'd need a thread per future, which is not exactly scalable. The article uses a pool which has its own problems.

The article even mentions an arguably better approach (check on a timer), but for some reasons claims it is worse.

Those integrations are not exactly good designs regardless; simply don't use std::future is the solution, and use non-blocking async mechanisms that can cooperate on the same thread instead. Standard C++ has one albeit somewhat overcomplicated, senders and receivers. Asio also works.

benreesman · 37m ago
An imperfect but really useful standard for whether or not a C++ feature is going to work out is how long and troublesome the standardization process is. Modules? Never happening boys, the time has passed when anyone cares. Coroutines? Break gdb forever? Keep dreaming.

Look at what they can do when it's clearly a good idea and has the backing of the absolute apex predator experts: reflection. If reflection can fucking sail through and your thing struggles, it's not going to make it.

Andrew Kelley just proposed the first plausible IO monad for a systems language, and if I wanted to stay relevant in async C++ innovation I'd just go copy it. Maybe invert the life/unlift direction.

The coroutines TS is heavily influenced by folly coroutines (or vice versa), a thing with which I have spent many a late night debugging segfaults. Not happening.

Besides, if threads are too slow or big now? Then everything but liburing is.

pjmlp · 25m ago
Not everyone is using C++ on Linux with GCC.

There are people where modules and co-routines already happened, and there is better debugging experiences out there than gdb.

cherryteastain · 31m ago
Coroutines are well supported in boost::asio and are deployed in production in more places than you would think.
benreesman · 24m ago
A second heuristic for things that aren't going to work out well is stuff that came from Boost. Oh sure, there was a time back in the TR11 days when it was practically part of the standard. But if it's on anyone's "cool, we'll link that, no problem" list in 2025? I don't know them.
OskarS · 43m ago
I think the idea is that you're using some external library (e.g. database drivers) which do not use asio but returns a std::future. You can't just "not use std::future" if that's what your library uses without fully rewriting your external library.

The other option is as you mention polling using a timer, but I don't see how that's better, I'd rather move the work off of the event loop to a thread. And you then have to do the "latency vs. CPU time" tradeoff dance, trying to judge how often to poll vs. how much latency you're willing to accept.

meindnoch · 3h ago
>The article even mentions an arguably better approach (check on a timer), but for some reasons claims it is worse.

How do you know what timeout to use for the timer? You may end up with tons of unnecessary polling if your timeout is too short, or high latency if your timeout is too long.

>Standard C++ has one albeit somewhat overcomplicated, senders and receivers

*in C++26

pjmlp · 22m ago
Or CUDA, which is getting its own compute version.
gpderetta · 3h ago
Boost also has a better future that at least allows composition.

But yes, do not use std::future except for the most simple tasks.

Davidbrcz · 2h ago
I work with C++, but the amount of don't use standard feature X because reason' is crazy.
account42 · 2h ago
It is a bit sad to see this for newer features. Maybe the committee should re-evaluate how quickly new designs are pushed into the standard and allow for a bit more time for evaluation. Moving fast makes sense when it's ok to break thinks, not so much when you need to support the result forever.
gpderetta · 3m ago
std::future was caught in coroutine/network/concurrency/parallelism master plan that has been redesigned way too many times. Sender/Receivers is the the current direction, and while I don't dislike it, we are still far for a final design to cover all use cases (we still don't have a sender/receiver network library proposal I think).

Whatever we end up with, std::future just wasn't a good base for an high performance async story. Still just adding a readiness callback to std::future would make it infinitely more useful even if suboptimal. At least it would be usable where performance is not a concern.

pjmlp · 19m ago
Although C++ is one of my favourite languages, I feel the current WG21 process is broken, it is one of the few language evolution processes where proposals are allowed to be voted in without any kind of preview implementation for community feedback, or even to actually validate the idea.

I have to acknowledge that none of the other ISO languages, including C, are this radical.

That is how we are getting so much warts of lately.

Unfortunelly there doesn't seem to exist any willingness to change this, until it will be too late to matter.

m-schuetz · 2h ago
On the contrary, I think they should move faster and provide more convenience functions that are "good enough" for 90% of use cases. For power users, there will always be a library that addresses domain-specific issues better than the standard could ever hope to.

Instead, the comitee attempts to work towards perfect solutions that don't exist, and ends up releasing overengineered stuff that is neither the most convenient, performant, nor efficient solution. Like <random>

pjmlp · 17m ago
And who gets to implement those ideas faster, many of which were never implemented before being added into the standard in first place?

The surviving three compilers are already lagging as it is, none of them is fully 100% C++20 compliant, C++23 might only become 100% on two of them, lets see how C++26 compliance turns out to be, meanwhile C++17 parallel algorithms are only fully available in one of them, while the two other ones require TBB and libstdc++ to actually make use of them.

lenkite · 41m ago
C++ really needs a fast-deprecate and kick out strategy for features that have proven to be poor - whether by bad design or bad implementation. And compilers should auto warn about such features.
Davidbrcz · 51m ago
I wouldn't mind if they actually _fix_ features afterward, even if it means breaking change.
usrnm · 5h ago
Every time I read an article like this I thank the day when I switched from C++ to go. I know why C++ is like this, I understand all the hard work that went into evolving it over 40 years, but I simply refuse to deal with all this stuff anymore. I have better things to worry about in my life.
IshKebab · 2h ago
Yeah... I used C++ coroutines a bit and they're super powerful and can do anything you want... But... I mean look at how complex co_await is:

https://en.cppreference.com/w/cpp/language/coroutines.html#c...

It does about 20 different steps with a ton of opportunities for overloading and type conversion. Insanely complicated!

And they kept up the pattern of throwing UB everywhere:

> Falling off the end of the coroutine is equivalent to co_return;, except that the behavior is undefined if no declarations of return_void can be found in the scope of Promise.

Why?? Clearly they have learnt nothing from decades of C++ bugs.

Hopefully Rust gets coroutines soon...

xialeistudio · 10h ago
In modern C++ development, coroutines have brought revolutionary changes to asynchronous programming. However, when using boost::asio or standalone asio, we often encounter scenarios where we need to convert traditional std::future<T> to asio::awaitable<T>. This article will detail an efficient, thread-safe conversion method.
userbinator · 6h ago
Did you just copy-paste the first paragraph of the article.
tgv · 34m ago
If you post to HN, you can choose between a text or a url. When you pick url, you can add some text, but it's added as a comment. I guess that's what happened.
vlovich123 · 5h ago
It's literally his article.
flakes · 5h ago
Seems prone to deadlocking- I would avoid making the thread-pool globally scoped, and instead provide it as arguments to the helper methods.