You’ve probably heard of multithreaded programs where a single process can have multiple threads of execution. But here is yet another layer of creating multitasking programs known as a fiber. [A Graphics Guy] lays it out in a lengthy but well-done post. There are examples for both x64 and arm64, although the post mainly focuses on x64 for Windows. However, the ideas will apply anywhere.
In the old days, there was a CPU and when your program ran on it, it was in control. But that’s wasteful, so software quickly moved to where many programs could share the CPU simultaneously. Then, as that got overloaded, computers got more CPUs. Most operating systems have the idea of a process, which is a program that thinks it is in complete control, but it is really sharing the CPU with other processes. The problem arises when you want to have multiple “little” programs that cooperate. Processes are not really supposed to know about one another and, if they do, there’s usually some heavy-weight communication mechanism allowing them to talk.
A thread, on the other hand, shares its variables and resources with other threads in the same process. In a multi-processor system, a program’s threads might run at the same time, or, in some cases, threads take turns running. For most cases, this is not a problem because many programs sit around waiting for some kind of I/O most of the time, anyway. But as [A Graphics Guy] mentions, video games and similar programs don’t work well with the typical thread scheduler, which tries to be fair and doesn’t really understand what the program is doing.
Another option is coroutines, where a program controls what is running (within its process). Some older operating systems worked this way. You ran until you decided you were at a good place to stop, and then you released to others, which is great until your program crashes, which is why you rarely see that at the top level anymore. Many C systems use longjmp as a way to let unrelated parts of the code switch between each other. C++ 20 introduced coroutines, too.
In fact, a fiber is an abstraction of this type of coroutine. In a practical operating system, a fiber works inside a thread, allowing the programmer to control their scheduling. Of course, the operating system still schedules among CPU cores, processes, and threads. But having, say, ten fibers will allow you to control how and when they execute better than creating ten threads and letting the operating system decide how they run.
The post provides an amazing amount of detail and compares fibers to C++ coroutines. Even if you aren’t writing games, the techniques here would be valuable in any sort of high-performance coding.