C++20 协程(Coroutines)代码示例
协程特别适合 **异步I/O**、**生成器** 和 **状态机** 等场景。| **异步任务**| `co_return` + `co_await`| 简化 `std::future` 风格代码|| **手动调度**| `std::coroutine_handle` | 低级别协程控制|std::this_thread::sleep_for(std::chrono::seconds(1));//
### **C++20 协程(Coroutines)代码示例**
C++20 引入了协程(Coroutines),它是一种轻量级的用户态线程,可以在不阻塞线程的情况下暂停和恢复函数执行。协程特别适合 **异步I/O**、**生成器** 和 **状态机** 等场景。
---
## **1. 基本协程示例(生成器模式)**
协程通过 `co_yield` 暂停执行并返回值,通过 `co_return` 结束执行。
### **示例:生成整数序列**
```cpp
#include <iostream>
#include <coroutine>
#include <memory>
// 1. 定义协程返回类型
struct Generator {
struct promise_type {
int current_value; // 当前生成的值
// 协程开始时调用
Generator get_return_object() {
return Generator(std::coroutine_handle<promise_type>::from_promise(*this));
}
// 初始挂起点
std::suspend_always initial_suspend() { return {}; }
// 协程结束时挂起(避免自动销毁)
std::suspend_always final_suspend() noexcept { return {}; }
// 处理 co_yield
std::suspend_always yield_value(int value) {
current_value = value;
return {};
}
// 处理 co_return
void return_void() {}
// 异常处理
void unhandled_exception() { std::terminate(); }
};
// 协程句柄
std::coroutine_handle<promise_type> coro;
// 构造函数
explicit Generator(std::coroutine_handle<promise_type> h) : coro(h) {}
// 析构时销毁协程
~Generator() {
if (coro) coro.destroy();
}
// 获取下一个值
int next() {
coro.resume(); // 恢复协程
return coro.promise().current_value;
}
};
// 2. 定义一个协程函数
Generator generateNumbers(int start, int end) {
for (int i = start; i <= end; ++i) {
co_yield i; // 暂停并返回值
}
co_return; // 结束协程
}
int main() {
// 3. 使用协程
Generator gen = generateNumbers(1, 5);
// 逐个获取值
std::cout << gen.next() << std::endl; // 1
std::cout << gen.next() << std::endl; // 2
std::cout << gen.next() << std::endl; // 3
std::cout << gen.next() << std::endl; // 4
std::cout << gen.next() << std::endl; // 5
return 0;
}
```
**输出**:
```
1
2
3
4
5
```
---
## **2. 异步任务(模拟 `std::future`)**
协程可以用于简化异步编程,模拟 `std::future` 的行为。
### **示例:异步计算**
```cpp
#include <iostream>
#include <coroutine>
#include <thread>
#include <chrono>
// 1. 定义异步任务类型
struct AsyncTask {
struct promise_type {
int result; // 存储计算结果
AsyncTask get_return_object() {
return AsyncTask(std::coroutine_handle<promise_type>::from_promise(*this));
}
std::suspend_never initial_suspend() { return {}; } // 立即执行
std::suspend_always final_suspend() noexcept { return {}; }
void return_value(int value) { result = value; } // co_return 返回值
void unhandled_exception() { std::terminate(); }
};
std::coroutine_handle<promise_type> coro;
explicit AsyncTask(std::coroutine_handle<promise_type> h) : coro(h) {}
~AsyncTask() { if (coro) coro.destroy(); }
int get() {
if (!coro.done()) {
coro.resume(); // 恢复协程(如果未完成)
}
return coro.promise().result;
}
};
// 2. 模拟耗时计算
AsyncTask computeAsync(int a, int b) {
std::cout << "Starting async computation..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟耗时
co_return a + b; // 返回结果
}
int main() {
// 3. 启动异步任务
AsyncTask task = computeAsync(10, 20);
std::cout << "Doing other work..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 获取结果(如果未完成,会等待)
std::cout << "Result: " << task.get() << std::endl; // 30
return 0;
}
```
**输出**:
```
Starting async computation...
Doing other work...
Result: 30
```
---
## **3. 协程与事件循环(模拟异步I/O)**
协程可以与事件循环结合,实现非阻塞I/O操作。
### **示例:模拟异步文件读取**
```cpp
#include <iostream>
#include <coroutine>
#include <functional>
// 1. 定义异步操作
struct AsyncRead {
struct promise_type {
std::string data; // 存储读取的数据
AsyncRead get_return_object() {
return AsyncRead(std::coroutine_handle<promise_type>::from_promise(*this));
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_value(std::string value) { data = value; }
void unhandled_exception() { std::terminate(); }
};
std::coroutine_handle<promise_type> coro;
explicit AsyncRead(std::coroutine_handle<promise_type> h) : coro(h) {}
~AsyncRead() { if (coro) coro.destroy(); }
std::string get() {
if (!coro.done()) coro.resume();
return coro.promise().data;
}
};
// 2. 模拟异步读取
AsyncRead readFileAsync() {
std::cout << "Start reading file..." << std::endl;
co_await std::suspend_always{}; // 模拟异步挂起
std::cout << "File read complete!" << std::endl;
co_return "File content: Hello, Coroutines!";
}
int main() {
AsyncRead reader = readFileAsync();
std::cout << "Doing other work..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << reader.get() << std::endl; // 获取文件内容
return 0;
}
```
**输出**:
```
Start reading file...
Doing other work...
File read complete!
File content: Hello, Coroutines!
```
---
## **4. 协程的底层控制(手动调度)**
可以通过自定义 `Awaiter` 控制协程的挂起和恢复逻辑。
### **示例:自定义 `Awaiter`**
```cpp
#include <iostream>
#include <coroutine>
struct MyAwaiter {
bool await_ready() const noexcept { return false; } // 总是挂起
void await_suspend(std::coroutine_handle<> h) const {
std::cout << "Suspended coroutine!" << std::endl;
h.resume(); // 立即恢复
}
void await_resume() const noexcept {
std::cout << "Resumed coroutine!" << std::endl;
}
};
struct Task {
struct promise_type {
Task get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() { std::terminate(); }
};
};
Task myCoroutine() {
std::cout << "Before await" << std::endl;
co_await MyAwaiter{}; // 自定义挂起/恢复逻辑
std::cout << "After await" << std::endl;
}
int main() {
myCoroutine();
return 0;
}
```
**输出**:
```
Before await
Suspended coroutine!
Resumed coroutine!
After await
```
---
## **总结**
| 场景 | 关键 API | 用途 |
|--------------------|-------------------------|-------------------------------|
| **生成器** | `co_yield` | 惰性生成序列(如 `range`) |
| **异步任务** | `co_return` + `co_await`| 简化 `std::future` 风格代码 |
| **事件驱动 I/O** | 自定义 `Awaiter` | 非阻塞操作(如网络请求) |
| **手动调度** | `std::coroutine_handle` | 低级别协程控制 |
**编译器支持**:
- GCC 10+ (`-fcoroutines`)
- Clang 12+ (`-fcoroutines-ts`)
- MSVC 2019+ (`/await`)
协程是 C++20 的重要特性,适合 **异步编程** 和 **生成器模式**,但需要一定的学习成本。
更多推荐
所有评论(0)