在C++20中引入的协程(coroutines)为异步编程提供了更直观、简洁的语法。它们允许函数在执行期间挂起(suspend)并在稍后恢复,而不需要手动管理状态机。本文将从底层原理、关键概念、典型用法以及实际案例几个角度来探讨C++20协程,并给出完整的代码示例。
1. 协程的基本构成
C++20的协程基于三个核心概念:
| 概念 | 作用 | 关键词 |
|---|---|---|
| Promise | 存放协程执行的上下文信息(如返回值、异常等) | promise_type |
| Handle | 用来控制协程的生命周期(resume, destroy) | std::coroutine_handle |
| Suspend Point | 协程的挂起位置 | co_await, co_yield, co_return |
协程函数的返回类型必须是某种“协程类型”,最常见的是 `std::generator
` 或自定义类型。标准库提供了 `std::generator` 用于生成序列,`std::async` 用于并发执行。 ## 2. 协程的执行流程 1. **创建协程** 调用协程函数时,编译器会生成一个 *promise* 对象并创建 *handle*。此时协程已准备好,但不会立即执行。 2. **初始挂起** 生成的代码在进入协程主体之前执行一次 `initial_suspend()`。如果返回 `std::suspend_always`,协程将挂起;如果返回 `std::suspend_never`,协程会立即开始执行。 3. **主体执行** 代码按正常顺序执行,遇到 `co_await`、`co_yield` 或 `co_return` 时会触发挂起,暂停当前协程,返回控制权给调用者。 4. **恢复** 调用者通过 `handle.resume()` 触发协程继续执行,直到下一个挂起点。 5. **完成** 当协程执行完毕或执行到 `co_return` 时,调用 `final_suspend()`。如果返回 `std::suspend_always`,协程会挂起,让调用者决定何时销毁;若返回 `std::suspend_never`,协程即刻销毁。 ## 3. 典型示例:异步文件读取 下面演示如何使用协程实现异步读取文件内容的简易框架。为了简化,示例中使用了同步IO,但演示的协程结构可以直接替换为真正的异步IO(如Boost.Asio、libuv等)。 “`cpp #include #include #include #include #include class AsyncRead { public: struct promise_type { AsyncRead get_return_object() { return AsyncRead{ std::coroutine_handle ::from_promise(*this) }; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void unhandled_exception() { std::terminate(); } void return_void() {} }; AsyncRead(std::coroutine_handle h) : handle(h) {} ~AsyncRead() { if (handle) handle.destroy(); } void resume() { handle.resume(); } bool done() const { return handle.done(); } private: std::coroutine_handle handle; }; AsyncRead readFileAsync(const std::string& path) { std::ifstream file(path, std::ios::binary); if (!file) { std::cerr buffer(1024); while (file) { file.read(buffer.data(), buffer.size()); std::size_t bytesRead = file.gcount(); std::cout {…}`。 ## 6. 进一步阅读 – 《C++20协程实战》 – 官方文档:`std::coroutine`, `std::generator` – 《Effective Modern C++》 (第 19 章:协程) – 《The Complete Guide to C++ Coroutines》 (社区文章) — 通过以上分析与代码示例,相信读者已经对C++20协程的原理、使用场景和实现细节有了清晰的认识。协程在异步编程、游戏引擎、网络服务等领域正逐渐成为不可或缺的工具,掌握其核心概念将大大提升代码的可读性和维护性。