C++20 通过协程(coroutines)引入了异步编程的新语法,显著简化了事件驱动程序、网络 I/O、协程式流水线等场景的实现。本文将从协程的基本概念、实现原理以及常见使用模式三方面展开说明。
1. 协程基础
1.1 什么是协程
协程是可以暂停执行、恢复执行的函数。与线程不同,协程不需要操作系统调度,它们的切换由程序员控制,切换成本极低。协程可用于实现非阻塞 I/O、生成器、状态机等。
1.2 C++20 的协程关键字
co_await:等待一个 awaitable 对象完成。co_yield:产生一个值并挂起。co_return:返回协程结果并结束。
协程函数必须返回 `std::experimental::generator
`、`std::future`、`std::generator`(C++23)或自定义的 `awaitable`,且其内部不能出现普通的 `return` 语句(只能使用 `co_return`)。 ## 2. 协程的实现原理 C++20 协程的实现基于“生成状态机”。编译器将协程函数展开为一个隐式生成的状态机类,包含以下关键部分: 1. **promise_type** 每个协程都有一个关联的 `promise_type`,负责协程的生命周期管理、异常传播、返回值包装等。 2. **悬挂点** 在 `co_await`、`co_yield`、`co_return` 处,协程会产生悬挂点,生成器状态机的 `resume` 方法会根据当前状态恢复执行。 3. **awaiter** `co_await` 需要一个 `awaiter` 对象,必须实现 `await_ready`、`await_suspend`、`await_resume` 三个成员函数。 4. **协程句柄** `std::coroutine_handle ` 用于对协程进行挂起/恢复、销毁等操作。 ### 2.1 典型流程 “` auto coro = my_coroutine(); // 调用时生成 promise_type 并返回句柄 coro.resume(); // 第一次 resume 开始执行 while (!coro.done()) { coro.resume(); // 持续恢复直到结束 } “` 在 `co_await` 处,`await_ready` 判断是否立即可用;若返回 `false`,则 `await_suspend` 将协程挂起,并将当前句柄传递给 awaiter;当 awaiter 完成后,`await_resume` 产生值,协程再次恢复。 ## 3. 常见使用模式 ### 3.1 异步 I/O 利用 `co_await` 与异步 I/O 库(如 Boost.Asio、libuv)配合,能够写出线性、易读的异步代码。 “`cpp #include using namespace boost::asio; awaitable async_echo(tcp::socket sock) { char data[1024]; std::size_t n = co_await sock.async_read_some(buffer(data), use_awaitable); co_await async_write(sock, buffer(data, n), use_awaitable); } “` ### 3.2 生成器 C++20 提供 `std::generator `,让 `co_yield` 成为生成器的天然语法。 “`cpp std::generator range(int start, int end) { for (int i = start; i