C++20 引入了协程(Coroutines),这是一种特殊的函数,它可以暂停执行并在之后恢复,而不是像普通函数那样一旦返回就终止。协程的主要特点在于它能保留自身的执行状态,这让异步编程更加简洁和直观。以下是对 C++20 协程的详细介绍:
关键概念
co_await
:这是一个操作符,用于暂停协程的执行,直至等待的异步操作完成。当异步操作完成后,协程会恢复执行。co_yield
:此操作符用于暂停协程的执行,并返回一个值给调用者。协程之后可以继续执行。co_return
:该操作符用于终止协程的执行,并返回一个值给调用者。
示例代码
下面的代码展示了一个简单的 C++20 协程示例:
#include <coroutine>
#include <iostream>
#include <stdexcept>
// 生成器类模板
template <typename T>
class Generator {
public:
struct promise_type {
T current_value; // 当前生成的数值
// 协程初始化时直接挂起(惰性执行)
std::suspend_always initial_suspend() noexcept { return {}; }
// 协程结束时保持挂起以便获取最终结果
std::suspend_always final_suspend() noexcept { return {}; }
// 协程返回时调用(无返回值)
void return_void() noexcept {}
// 处理未捕获的异常
void unhandled_exception() { throw; }
// 生成器构造入口
Generator get_return_object() {
return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
}
// 定义 co_yield 行为
std::suspend_always yield_value(T value) {
current_value = value;
return {};
}
};
// 协程句柄
std::coroutine_handle<promise_type> coro_handle;
// 构造函数
explicit Generator(std::coroutine_handle<promise_type> h) : coro_handle(h) {}
// 析构时销毁协程
~Generator() { if (coro_handle) coro_handle.destroy(); }
// 迭代器支持
bool move_next() {
if (!coro_handle.done()) {
coro_handle.resume();
return !coro_handle.done();
}
return false;
}
T current() const { return coro_handle.promise().current_value; }
// 范围遍历支持
struct Iter {
Generator& gen;
bool operator!=(std::nullptr_t) const { return gen.move_next(); }
void operator++() {}
T operator*() const { return gen.current(); }
};
Iter begin() { return Iter{*this}; }
std::nullptr_t end() { return nullptr; }
};
// 生成整数序列的协程函数
Generator<int> generate_sequence(int start, int end) {
for (int i = start; i <= end; ++i) {
co_yield i; // 每次生成一个值并挂起
}
}
int main() {
// 生成 1 到 10 的序列
auto seq = generate_sequence(1, 10);
// 遍历输出
for (auto num : seq) {
std::cout << num << " ";
}
// 输出: 1 2 3 4 5 6 7 8 9 10
}
代码解释
Task
结构体:它是协程的返回类型,包含了promise_type
结构体,用于定义协程的行为。coroutineFunction
函数:这是一个协程函数,使用co_await std::suspend_always{}
来暂停协程的执行,然后使用co_return 42
来终止协程并返回值 42。main
函数:调用coroutineFunction
函数获取协程对象,然后调用get
方法获取协程的返回值并输出。
这个示例只是一个简单的演示,在实际应用中,协程通常会用于处理异步 I/O 操作,以提高程序的性能和响应能力。