29:12 The point of enable_shared_from_this is **NOT** that you “just write a deleter that joins scheduled work”, the whole point is that the object stays alive until all scheduled work was completed. So you do not have to deal with any asynchronous operations in its destructor
The question was "how to handle classes which need asynch cleanup and are stored in a shared pointer". The answer is that there isn't a good solution, but in our use cases a class which needs async cleanup is generally a local variable and we can join it in the function. The async cleanup is normally the logic which guarantees that all the work has been joined before destruction. If you're designing a system where the class is stored in a shared pointer held only by each unit of work, you could assert in the destructor that all async work is done. But that is not the approach followed by structured concurrency, which instead allows not to have to store state in shared pointers because the unit of work just get references to the class, and the scheduling of work is done in a way that the reference remains alive for the duration of all the work
Not sure about a released version, but if you build llvm from source, you can try it out. Similarly, cmake 3.28 with ninja can be used as a build generator.
You can already use modules in gcc and clang, however the standard lib hasn't been exposed as a module yet, you can still include it within a module though
@RoiEXLab @arthurozga2722 Thank you for your replies. I'm talking fully fledged implementation with all bells and whistles i can build a code base on, not playing around without stdlib or some esoteric b2 compiler examples. I've tried since 2017 if I remember correctly and it always breaks for my use cases once I go beyond basics.
Half of issues is because coroutines are executed in different threads. Question: wtf? Why in hell anyone would do it? Coroutine is sugar, therefore, it is completely up to user to guard itself.
That's precisely what I'm thinking. It's just a syntactic sugar wrapper around threads anyway. Back some 20-ish years ago I toyed with coroutines in C and none of it was threaded or asynchronous. The whole reason for using them was to avoid threads and locking code while still allowing lazy evaluation, but modern implementations all seem to use threads. Truthfully, I find proper full threads to be easier to use and don't understand why anyone would use or want to use modern coroutines.
Whether the coroutine is executed in multiple threads or not depends on the executor on which it's executed. If for your use case a single threaded model is the correct one, you can use that and not care about synchronization. But there are many cases in which you want to make use of multiple threads to parallelize the work, and coroutines support that. The talk calls out some of the things that need to be taken into account in such cases. I hope this helps :)
I've watched Eric Niebler and many others on coroutines now and I *cannot* for the life of me tell what coroutines are supposed to solve. This talk is titled "problems and solutions", and I thought I'd see examples of problems coroutines solves, but no, it's about problems coroutines *introduces*. If that's not a red flag, you need to get your eyes checked. Let me TL;DR coroutines for you: they're over-engineered std::function that uses a whole new set of keywords and nomenclature so that you have no clue what's going on and dangles references left, right and center. If someone has a concrete example where coroutines are indispensable, I will gladly be corrected.
Example: You are writing a server component, which receives requests from users for songs, picks them from database and sends them back to user. You can use threads and then wait for user request doing nothing, then send song request to the database and wait for it doing nothing and then send the song. Each thread can handle exactly one user request at a time. You can use epoll/uring to fix sync waiting but their interfaces are rather user unfriendly, they are platform dependent and also don't perform all that well when overloaded since they are points of contention. Finally you can use coroutines (or stackful fibers): every time you *wait* your execution actually pauses and the executing thread can pick another task. E.g. while you are waiting for user request, thread can handle older requests to database which are finally fulfilled or handle another user requests. So in cases 2 and 3 you have multiple requests handled per 1 thread at a time. 2 is worse because it's harder to use and runs worse when scale (millions of requests) is taken into the account
Coroutines are not indispensable in any case since they are syntactic sugar for continuation passing style, which is very common in asynchronous code. But if that isn't something you need, coroutines are not aimed to improve your situation. When they are a good fit, it's a nice addition. Which unfortunately, like almost everything in C++, comes with some pitfalls, which this talk aims to uncover and provide possible mitigations for.