I looked at this question: Is seastar::thread a stackful coroutine?
In a comment to the answer, Botond Dénes wrote:
That said, seastar::thread still has its (niche) uses in the post-coroutine world as it supports things like waiting for futures in destructors and catch clauses, allowing for using RAII and cleaner error handling. This is something that coroutines don't and can't support.
Could someone elaborate on this? What are the cases when 'things like waiting for futures in destructors and catch clauses' are impossible with stackless coroutines, but possible with seastar::thread
(and alike)?
And more generally, what are the advantages of seastar::thread
over C++20 stackless coroutines? Do all stackful coroutine implementations (e.g. those in Boost) have these same advantages?
You have probably heard about the RAII (resource acquisition is initialization) idiom in C++, which is very useful for ensuring that resources get released even in case of exceptions. In the classic, synchronous, C++ world, here is an example:
Now, let's consider asynchronous code using Seastar. Imagine that
get_an_o()
takes some time to do its work (e.g., open a disk file), and returns afuture<someobject>
. Well, you might think that you can just use stackless coroutines like this:But there's a problem here... Although the
someobject
constructor could be made asynchronous (by using a factory function,get_an_o()
in this example), thesomeobject
destructor is still synchronous... It gets called by C++ when unwinding the stack, and it can't return a future! So if the object's destructor does need to wait (e.g., to flush the file), you can't use RAII.Using a
seastar::thread
allows you to still use RAII because the destructor now can wait. This is because in aseastar::thread
any code - including a destructor, may useget()
on a future. This doesn't return a future from the destructor (which we can't) - instead it just "pauses" the stackful coroutine (switches to other tasks and later returns back to this stack when the future resolves).