Tag Archives: fiber

An example of `boost::fiber`

Fiber is just a thread implemented in user space. Fibers are easier to reason about and have the performance advantage of much cheaper context switching. Fibers are very well-suited for handling concurrent I/O operations where a processor mostly waits for data to become available; threads usually have a pretty high context-switching cost. Therefore, multiple fibers running in a single thread is an effective solution.

Here is a simple program I wrote to explore fibers. You can find the full example below. This program has two functions: print_a prints “a,” and print_b prints “b” and then launches a thread that prints “B” (in detached mode).

void print_a()
{
    cout << "a";
    boost::this_fiber::yield();
}

void print_b()
{
    cout << "b";
    std::thread j([]() { printf("B"); });
    j.detach();
    boost::this_fiber::yield();
}

Following is the main function. We created a shared variable i initialized to 0. We create two detached fibers. The first one keeps calling print_a until i < 20. Similarly, the second one loops on print_b until i < 20. Both increment i by 1. When i = 20, both fibers should be able to join.

int main()
{
    int i = 0;
    boost::fibers::fiber([&]() {
        do {
            print_a();
            i++;
        }
        while (i < 20);
    }).detach();

    boost::fibers::fiber([&]() {
        do {
            i++;
            print_b();
        } while (i < 20);
    }).detach();

    printf("X");
    return 0;
}

Let’s guess the output of this program. It is most likely to be the same as if std::threads were used instead of fibers.

Is “X” printed first? Yes. Note that detach() is called on each fiber, so neither of their functions is called immediately. They are put in the background. Control passes to the fiber manager at return 0;, which is when it asks the fibers to join. In fact, you can put more computations after the printf("X"); statement, and they would be computed before any fiber is called.

As soon as we try to return from main, the fiber manager is asked to join the fibers. The first fiber wakes up, “a” is printed, and the fiber yields control to the manager. The fiber manager then wakes up the second fiber (which was waiting in the queue), which prints “b” and also launches a thread in the background that prints “B”. We cannot be sure if “B” will be printed immediately after “b” (since it is a std::thread). print_b yields control and goes to sleep. The fiber manager wakes up the first fiber again, print_a is called, “a” is printed, and so on. Note that i is incremented every time either of the fibers is called.

When i hits 20, both fibers terminate and join, and the main function executes return 0;. Consequently, print_a is called ten times, and print_b is also called ten times. In the output, we should have ten “a”s, ten “b”s, and ten “B”s. “B” may not strictly follow “b,” but “b” must come after “a.”

Here are a few runs of the program. Note that the location of “B” is not deterministic.

XababBabBabBababBBabBabBabBabBB 
XababBabBabBabBabBabBabaBbBabBB 
XababBabBabBabBabBabBabBabBabBB 
XababBabBabBabBabBabBabBabBabBB 
XababBabBabBBababBabBabBabBabBB 
XababBabBabBabBabBabBabBabBabBB 
XababBabBabBababBBabBabBababBBB 
XababBabBabBababBBabBabBabBabBB 
XababBabBabBababBBabBabBabBabBB 
XababBabBabBabBabBababBBabBabBB 
XababBabBabBabBabBabBabBabBabBB

References A great talk by Nat on Boost fibers: https://youtu.be/e-NUmyBou8Q