Coroutines (C++20)
Cooperative multitasking with suspendable functions
What Are Coroutines?
Coroutines are functions that can suspend execution and resume later, enabling cooperative multitasking without threads.
// Three coroutine keywords:
// co_await - suspend execution, wait for completion
// co_yield - produce a value and suspend
// co_return - return from coroutine
// Example: Simple generator (C++23 std::generator simplifies this)
std::generator<int> count_to(int n) {
for (int i = 0; i < n; ++i) {
co_yield i; // Produce value, suspend
}
// Implicit co_return at end
}Coroutine Components
Promise Type
Defines coroutine behavior: initial/final suspend points, return value handling, exception handling, and yield behavior.
Coroutine Handle
Low-level control over coroutine execution: resume, destroy, check done.
Awaitable
Objects that can be awaited with co_await. Define when to suspend/resume.
Return Object
What the caller receives when invoking a coroutine (e.g., std::generator, Task).
C++23 std::generator
C++23 provides std::generator, eliminating the need for custom promise types in most cases.
#include <generator>
#include <ranges>
// Simple generator function
std::generator<int> fibonacci() {
int a = 0, b = 1;
while (true) {
co_yield a;
int next = a + b;
a = b;
b = next;
}
}
// Works with ranges
void use_generator() {
for (int n : fibonacci() | std::views::take(10)) {
std::cout << n << " ";
}
// Output: 0 1 1 2 3 5 8 13 21 34
}
// Recursive generators
std::generator<int> tree_traversal(Node* root) {
if (!root) co_return;
for (int val : tree_traversal(root->left)) {
co_yield val;
}
co_yield root->value;
for (int val : tree_traversal(root->right)) {
co_yield val;
}
}When to Use Coroutines
- ✓Lazy sequences (infinite or large data sets)
- ✓Asynchronous I/O operations
- ✓Event-driven programming (state machines)
- ✓Cooperative multitasking
- ✗Simple iterations (use regular loops)
- ✗Parallel computation (use threads)
Best Practices
- ✓Use C++23 std::generator for sequence generation
- ✓Handle coroutine lifetimes carefully (don't leak)
- ✓Mark noexcept when coroutine doesn't throw
- ✗Don't mix coroutines with traditional callback patterns without care