If you are reading this post you are probably already familiar with the concept of coroutine.
If you are not, let’s say coroutines are a way to have cooperative (non pre-emptive) multitasking, possibly on a single thread. You can have multiple flows of execution that yield control to each other without being pre-empted, and without using threads, semaphores, and condition variables. In simple terms, coroutines are an extension to the concept of function: while functions cannot be resumed after “returning,” coroutines can be resumed from where they were suspended when “yielding” to another coroutine.
There is no language support in C++ for coroutines, but some libraries are available, that use some platform-specific code and a few ingenious hacks to make coroutines possible in C++. A noteworthy one is Boost.Coroutine, based on Boost.Context, a low-level library capable of doing the “magic” of a userspace context switch.
I had problems myself understanding coroutines when I saw them for the first time, and I consistently find it difficult to explain them to other developers, however smart and experienced. I think that parsing stream data is a good case study that makes it immediately understandable what coroutines can give you in real-world applications. When you parse data coming from a stream you have limited control on (e.g. a socket), you often end up coding a state machine that consumes one byte at a time, as the data you are parsing may be coming to you chunked in various ways. In this post, I will introduce a simple C++ example of a coroutine-based parser, present a few benchmarks, and try to cause in you mixed feelings about Boost.Coroutine by showing you a few pros and cons of using it. Read more...