Live data from Hacker News

Fiber in C++: Understanding the Basics

agraphicsguynotes.com

71–77 of 77 posts

Re: Fiber in C++: Understanding the Basics

#71

I'm confused in how this article defines "fiber." At the beginning of the article, fibers are described as a lightweight userspace thread, similar to what is provided in the runtimes of Haskell and Go, and has been recently revived in Java as "virtual threads." However, later in the article (after a long and apparently irrelevant digression about stack management), they describe Windows API functions that are require…

"Fibers", "green threads", "stack switching", "cooperative multitasking" are essentially all the same thing, they all rely on being able to switch execution context by switching to a different stack within the same OS thread. As such they can be implemented either in (CPU/OS-specific) user code or in "OS APIs" (like the Windows Fiber functions). Only downside of the technique is that it cannot be implemented in WASM…

I've always been curious why WASM has the program flow restrictions it has. Most "ASM" just lets you set whatever register.

There isn't much sandboxing value (WASM shouldn't be able to touch addresses outside the sandbox anyways). Was the reason ease of compilation/optimization for arbitrary architectures? Easier to run inside an interpreter?

The default idea for WASM feels like it should have been more like RISC-V (but with enough wiggle-room to allow easy JITing to x86/ARM).

Or are most of WASM's quirks just because it has ASM.js in its lineage?

Re: Fiber in C++: Understanding the Basics

#72

Earlier quoted context omitted.

Thanks, stackful/stackless is noted for next time. I still kinda like using "async" as a shorthand for stackless coroutines though.

Before async for I/O became popular, stackless coroutines were mainly used for generator abstractions (for example yield in python), so async can be reductive.

And that's exactly why I would say "async", because then everyone will know that I'm talking about something like async in Python/C#, and not something like Python generators.

Technically, they're may well be almost the same thing, but practically, they're used very differently.

Re: Fiber in C++: Understanding the Basics

#73
Thank you for this in-depth article.

I am a less than a C++ beginner but I asked Stack Overflow how to run C++ coroutines in a thread pool. It seems coroutines in C++20 are unfinalised but don't quote me on that but I did get some sourcecode for older versions of the C++20 standard.

I used Marce's Coll's excellent blog post about how to create coroutines in assembly by adjusting the RSP register.

https://blog.dziban.net/posts/coroutines/

I extended Marce's code to run the coroutines in kernel threads:

https://github.com/samsquire/assembly (see threadedcoroutines.S)

I have been thinking of coroutines in terms of query compilation for database engines and the volcano query model and this article:

https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

Tying together two pieces of code that call eachother in push or pull driven style is really powerful. Or if you're running multiple independent tasks that need their own state. This as I understand it is the original intent of object orientation that Alan Kay wanted and is represented by Erlang and partly Go.

Specifically, I am thinking of compiler created coroutines where code can be interleaved at compile time rather than at runtime.

Re: Fiber in C++: Understanding the Basics

#74

Earlier quoted context omitted.

This doesn't address the shadow stack at all. It doesn't work.

Each instance has its own stack. Switching between them is cooperative on a single thread. What am I missing?

WebAssembly stores stack data - parameters, return addresses, local variables - in a "shadow stack" that does not live in the native heap your application has access to. There's no way for you to switch it.

Re: Fiber in C++: Understanding the Basics

#75

I'm confused in how this article defines "fiber." At the beginning of the article, fibers are described as a lightweight userspace thread, similar to what is provided in the runtimes of Haskell and Go, and has been recently revived in Java as "virtual threads." However, later in the article (after a long and apparently irrelevant digression about stack management), they describe Windows API functions that are require…

Setting aside certain implementation details, here's the basics: Kernel Threads (aka threads): OS-Level and preemptive. Green Threads (aka lightweight threads, virtual threads or goroutines): User-level and preemptive. Fibers: User-level (sometimes OS-level or offered as a OS library, like in Windows) and cooperative. Coroutines: User-level and cooperative.

The devil's in the implementation details though. The operating system may provide both fully-preemptive threads on which to schedule user space cooperative threads (scheduling on system call). At that point green threads (e.g. threading implemented by a virtual machine on top of the operating system) do not provide the same value. This is actually why Green threads were effectively pulled out of Java for a few decades.

Fibers are distinct in that they have no scheduling and are code being run on a thread - if the thread is preempted, it will resume on that same thread. Unlike cooperative threading, they must explicitly yield.

Coroutines have such varying implementations that you would need to define requirements to know if they count as fibers or not - for instance, whether you mandate a C-compatible stack.

Re: Fiber in C++: Understanding the Basics

#76
post #63

I believe that fibers are considered more trouble than they worth? [0] [0] https://devblogs.microsoft.com/oldnewthing/20191011-00/?p=10...

The Gor Nishanov paper linked in that piece goes into a lot of detail of some of the downsides of fibers in an unmanaged language like C++. [0] http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p136...

Thanks for the link to the Gor's paper.

Apparently the 2018 paper table only covered top 10 languages in the TIOBE index, I wished it can be updated and extended further to top 50 languages.

Another popular compiled language with GC (by default) namely D language (TIOBE ranked 37 as of Sept 2023) does support fiber and it's implemented in its vibe.d web framework [1],[2].

Gor also mentioned about significant 160 ns overhead for stackful fiber in Go (goroutine) to interact with a C library i.e. cost of switching between Go's goroutines and C threads (as of 2018). It will be interesting to know the fiber overhead in D language since C compilation is now natively supported by D compiler [3].

[1] Fibers in Programming in D:

https://ddili.org/ders/d.en/fibers.html

[2] Fibers, what for:

https://forum.dlang.org/thread/eowfajvnzqnncmfnjhnf@forum.dl...

[3] Adding ANSI C11 C compiler to D so it can import and compile C files directly:

https://news.ycombinator.com/item?id=27102584

Re: Fiber in C++: Understanding the Basics

#77

Earlier quoted context omitted.

Each instance has its own stack. Switching between them is cooperative on a single thread. What am I missing?

WebAssembly stores stack data - parameters, return addresses, local variables - in a "shadow stack" that does not live in the native heap your application has access to. There's no way for you to switch it.

Each instantiated module has its own complete function call stack. A call out of the module, to a bit of control code in JS, and then into a different instance of the same module, with the same memory mappings, would look (to the program itself) like a stack switch, no?

I guess it raises the philosophical question of what is a stack switch, anyway? If you end up cooperatively running multiple "green threads" within a single "OS thread" does it matter that what you actually switched was the entire execution environment?

Post reply on HN