Since coroutines have been in the standard since C++20, I wish he would have explained better what are the advantages of using a Fiber over a Coroutine.
Advantage: No function colouring. Just like with threads, you don't need to declare which functions might potentially yield. There's none of that noisy async/await syntax. Advantage: Fast switching. Switching between fibers is done by swapping in new values for the program counter and stack pointer. Compare with async, where yielding only takes you up one level of stack, so your code ends up walking a stack of corout…
Fiber in C++: Understanding the Basics
51–60 of 77 posts
Re: Fiber in C++: Understanding the Basics
#52Earlier quoted context omitted.
Having a native stack switch for WASM would be nice but it's not necessary. Map all memory segments as shared into several instances of a single module -- each instance is a fiber. Implementation is left as an exercise for the reader.
This doesn't address the shadow stack at all. It doesn't work.
Re: Fiber in C++: Understanding the Basics
#53Still looking for a lib that supports fibers... boost::asio is... well, boost, and therefore annoying. It also does not support it out of the box
Re: Fiber in C++: Understanding the Basics
#54Earlier quoted context omitted.
Windows had a custom scheduler API ( https://learn.microsoft.com/en-us/windows/win32/procthread/u... ) but they removed it, presumably because it wasn't used much
As the Wikipedia page shows, NetBSD had an implementation but later removed it. There isn't really enough information to make a sound judgement on scheduler activations. Although if I had to guess, there might be too much overhead (maintenance of code and/or actual performance) for something that is rarely used. It might make more sense now that we're moving towards user-level concurrency everywhere (async/await, gor…
So, at least at that time, M:N and scheduler activation was a solution in search of a problem. It might still see a resurgence on one way or another.
Re: Fiber in C++: Understanding the Basics
#55Earlier quoted context omitted.
Advantage: No function colouring. Just like with threads, you don't need to declare which functions might potentially yield. There's none of that noisy async/await syntax. Advantage: Fast switching. Switching between fibers is done by swapping in new values for the program counter and stack pointer. Compare with async, where yielding only takes you up one level of stack, so your code ends up walking a stack of corout…
Fun fact, what you call async is also widely referred to as coroutines. Stackless coroutines vs stackful coroutines seems like the most appropriate way to disambiguate the two.
Re: Fiber in C++: Understanding the Basics
#56Earlier quoted context omitted.
> exception safe, because you need to save/restore exception globals when switching fibers, Do you have more details about this issue? What exception globals? And for which ABI? You mean some sort of current pending exception when switching during unwinding? [I'm a huge fan of stackful coroutines and I wish were blessed by the standard]
C++ ABI has some per-thread globals: the number that is returned from std::uncaught_exceptions(), and the chain of currently caught exceptions. For example in llvm this is available with a cxa_get_globals call: https://github.com/llvm/llvm-project/blob/b05f1d93469fbd6451... These need to be saved/restored when switching fibers, otherwise fiber switches from catch clauses (and destructors!) are unsafe, throw without a…
It is another reason for having this built into the language/standard library so that it can be implemented optimally.
Re: Fiber in C++: Understanding the Basics
#57Earlier quoted context omitted.
A disadvantage of the ‘no function coloring’ in fibers is that it makes lockless programming harder. A nested function call can switch from under you without your knowledge, making it hard to know where the preemption points are and whether to take locks when making updates to shared state. With function coloring you immediately see whether a function might switch as there’s a different calling syntax. I’ve programme…
[I assume you are using lock free in a loose way, as lacking explicit mutual exclusion]. In practice in most real world applications in C++, absence of async calls is not enough to guard against re-entrancy. Shared state might still be mutated by callbacks, by recursively re-entering the event loop or by other threads. So you need to either document explicitly all the assumptions you are making and vet every single f…
I agree that using explicitly switched coroutines is not sufficient for mostly “lockless” programming (but I do think it’s necessary). I was coming from a thread per core perspective where you run one event loop per core and limit cross core communications (like in the Seastar framework). With this you should be able to perform most state manipulations without locks.
Re: Fiber in C++: Understanding the Basics
#58Earlier quoted context omitted.
As the Wikipedia page shows, NetBSD had an implementation but later removed it. There isn't really enough information to make a sound judgement on scheduler activations. Although if I had to guess, there might be too much overhead (maintenance of code and/or actual performance) for something that is rarely used. It might make more sense now that we're moving towards user-level concurrency everywhere (async/await, gor…
Basically yes. M:N just wasn't a good fit for the way applications used (and use) pthreads. For those that need pure CPU parallelism M:N is just useless overhead, while highly concurrent applications were either using one process per request for simplicity and robustness, or directly building on top of poll/epoll/kqueue for performance. So, at least at that time, M:N and scheduler activation was a solution in search…
Even with N:N architecture, if one kernel thread blocks (say, on I/O), the point is for the user-space scheduler to decide which thread should run next. The point was that the kernel scheduler cannot/should not understand the application thread scheduling requirements, and that when a kernel thread allocated to the task blocks, only user space can (correctly) decide what to do.
Re: Fiber in C++: Understanding the Basics
#59Remind me again why no OS other than Solaris ever provided "scheduler activations" (i.e. the kernel calls back into a user-space scheduler whenever a kernel-level scheduling event occurs)
Re: Fiber in C++: Understanding the Basics
#60Earlier quoted context omitted.
The Windows fiber library is just that, a library. It's not an OS component. It's provided because stack switching in Windows is a somewhat fraught [1] and not officially documented procedure which requires modifying the TIB [2]. Doing it correctly isn't hard, and has been done many times in bullet-proof libs (notably boost::context), but MS would maybe rather you not. [1]: https://devblogs.microsoft.com/oldnewthing/…
It is an OS component, it's provided in kernel32.dll and accesses internal OS data structures that are not publicly defined or stable between versions. You cannot safely implement fibers in Windows without the fibers API, period. Boost.Context's direct Windows context switching code hacks undocumented fields in the TIB: https://github.com/boostorg/context/blob/6fa6d5c50d120e69b2d... ...and this causes problems, becau…
I already said "MS would rather you not", obviously, otherwise they would have documented the TIB.
The fact remains that tons of production systems rely on officially-unofficial elements of NT's architecture and this is one such element that is heavily relied on by everyone who uses boost stackful coroutines. Hyrum's Law in action.