Coroutines are a major addition to the C++20 language standard, and so should be interesting to anyone wishing to develop their use of Modern C++. Coroutines are different to threads (which have been standardized since C++11) and are considerably more lightweight in their Standard Library implementation, requiring just the <coroutine> header. An imperfect analogy could be that threads are similar to pre-emptive multitasking, while coroutines tend to mirror co-operative multitasking. Coroutines are not a replacement for threads, and the two can usefully co-exist; a coroutine can be paused on one thread and re-started on another, for example. An attractive feature of coroutines is that they are less susceptible to data races, deadlock, and some of the other pitfalls when using threads.
So the down side? While the change to the language itself is only the addition of three new keywords, co_await, co_yield and co_return, a large amount of boilerplate (even by C++ standards) is needed to allow them to do anything useful. There is a three-way interaction between the language keywords used in your coroutine code, the Standard Library implementation, and the boilerplate they require as the “glue” between them. This article intends to cover co_yield, with a focus on getting it to act like Python’s yield keyword when constructing generators.
Continue reading “C++ Coroutines Primer (1)” →