Coroutines are a powerful feature introduced in C++20 that facilitate writing asynchronous and sequential code. They allow you to suspend and resume the execution of a function, making it easier to write code that involves tasks or operations with non-blocking behavior.
In C++, there are two types of coroutines, which define the behavior of coroutines and how they interact with other code:
1. Generator Coroutines
Generator coroutines are used to generate a sequence of values that can be iterated over. They are defined using the generator
keyword and can return multiple results over time.
#include <iostream>
#include <coroutine>
std::coroutine_handle<> generator_coroutine() {
struct generator {
int current_value;
bool move_next() {
if (current_value < 10) {
++current_value;
return true;
}
return false;
}
int current() {
return current_value;
}
};
struct promise_type {
generator get_return_object() {
return generator{.current_value = 0};
}
std::suspend_never initial_suspend() noexcept {
return {};
}
std::suspend_never final_suspend() noexcept {
return {};
}
void return_void() {}
void unhandled_exception() {}
};
return std::coroutine_handle<promise_type>::from_promise(promise_type{});
}
int main() {
auto coroutine = generator_coroutine();
while (coroutine.move_next()) {
std::cout << coroutine.promise().current() << " ";
}
return 0;
}
In this example, the generator_coroutine
function returns a generator
object that can be used to iterate over a sequence of values from 1 to 10. The current
function returns the current value, and move_next
is used to advance to the next value. The promise_type
is responsible for handling the coroutine’s lifetime and behavior.
2. Async Coroutines
Async coroutines are used to perform asynchronous operations, such as waiting for I/O or network requests. They are defined using the async
keyword and allow you to write code that appears to be synchronous, even though it’s executing asynchronously.
#include <iostream>
#include <experimental/coroutine>
#include <chrono>
#include <thread>
std::experimental::suspend_always delay_coroutine(int seconds) {
std::this_thread::sleep_for(std::chrono::seconds(seconds));
co_return;
}
std::experimental::suspend_never async_coroutine() {
co_await delay_coroutine(2);
std::cout << "Async coroutine executed after 2 seconds" << std::endl;
co_return;
}
int main() {
async_coroutine();
std::cout << "Main function continues executing" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
return 0;
}
In this example, the delay_coroutine
suspends the coroutine for a specified number of seconds before resuming execution. The async_coroutine
uses co_await
to wait for the delay coroutine to complete before printing a message. The main
function demonstrates the asynchronous behavior by continuing execution while the async coroutine is suspended.
Coroutines in C++ provide a powerful mechanism for writing clean and efficient asynchronous code. Understanding the different types of coroutines available can help you leverage their capabilities and unlock their full potential in your applications.
#cpp #coroutines