A Minimal but Complete Example
Learn how to create a fully functional coroutine example by learning about the return object, promise type, awaitable types, passing the coroutine around, and allocating its state.
Overview
Let’s start with a minimal example to understand how coroutines work. Firstly, we implement a small coroutine that is suspended and resumed before it returns:
Secondly, we create the caller of the coroutine. Pay attention to the output and the control flow of this program. Here it is:
Thirdly, the return object of the coroutine, Resumable, needs to be defined:
Finally, the promise type is implemented as a nested class inside the Resumable, like this:
This example is minimal but walks through a lot of things that are worth paying attention to and need to be understood:
- The function
coroutine()is a coroutine because it contains the explicit suspend/resume point usingco_await - The coroutine doesn’t yield any values but still needs to return a type (the
Resumable) with certain constraints so that the caller can resume the coroutine - We are using an awaitable type called
std::suspend_always - The
resume()function of the resumable object resumes the coroutine from the point it was suspended - The
Resumableis the owner of the coroutine state. When theResumableobject is destructed, it destroys the coroutine using thecoroutine_handle
The relationship between the caller, the coroutine, the coroutine handle, the promise, and the resumable is illustrated in the following diagram:
Now it’s time to look a little closer at each part. We’ll begin with the Resumable type.
The coroutine return object
Our coroutine returns an object of type Resumable. This Resumable ...