从C++11到C++20:标准库中的协程实现与实践

协程(coroutine)是指在函数执行过程中能够挂起并在后续恢复执行的机制,它让异步编程变得更加直观。C++自从引入了协程的概念后,标准库逐步完善了对协程的支持,尤其在C++20标准中正式加入了std::generatorstd::task以及co_await等语法糖。本文将从历史变迁、核心概念、实现细节以及实际应用四个方面,系统梳理C++协程的演进与使用技巧。

1. 协程的历史回顾

版本 关键特性 说明
C++11 std::future, std::async 基础异步支持,线程池实现
C++14 std::experimental::generator 早期实验性协程实现,使用yield
C++17 std::experimental::coroutine 更完整的协程框架,定义了promise_type
C++20 std::generator, std::task, co_await, co_yield 标准化协程,提供了编译器内置支持

从C++14开始,编译器已逐步支持协程的语法,但缺乏标准化的库封装。C++20则彻底将协程纳入标准,使其可在任何符合标准的编译器上使用。

2. 核心概念解析

2.1 协程函数

协程函数与普通函数不同,它不一定会一次性返回,而是可以在执行过程中挂起(co_yield)或等待异步结果(co_await),最终完成时返回voidstd::future或自定义类型。

std::generator <int> range(int n) {
    for (int i = 0; i < n; ++i) co_yield i;
}

2.2 Promise 与 Awaiter

  • promise_type:协程的状态机,负责在协程开始、挂起和结束时进行资源管理。
  • awaiter:与co_await配合使用,定义await_readyawait_suspendawait_resume三个成员函数。

2.3 Coroutine Handle

`std::coroutine_handle

`用于直接控制协程的生命周期,例如显式挂起或恢复。 ## 3. 实际实现:自定义 `AsyncFileReader` 下面给出一个基于C++20协程的异步文件读取器,它在后台线程中读取文件内容,然后通过协程返回读取的行。 “`cpp #include #include #include #include #include #include #include #include class AsyncLineReader { public: struct promise_type { AsyncLineReader get_return_object() { return AsyncLineReader{std::coroutine_handle ::from_promise(*this)}; } std::suspend_never initial_suspend() noexcept { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() { std::terminate(); } }; using handle_t = std::coroutine_handle ; explicit AsyncLineReader(handle_t h) : coro(h) {} AsyncLineReader(const AsyncLineReader&) = delete; AsyncLineReader& operator=(const AsyncLineReader&) = delete; AsyncLineReader(AsyncLineReader&& other) noexcept : coro(other.coro) { other.coro = nullptr; } ~AsyncLineReader() { if (coro) coro.destroy(); } // 取得下一行,若已读取完返回空字符串 std::string next() { if (!coro || coro.done()) return “”; coro.resume(); return line; } private: handle_t coro; std::string line; static std::string read_next_line(std::ifstream& fin) { std::string tmp; return (std::getline(fin, tmp)) ? tmp : std::string(); } // 协程体 static AsyncLineReader* current; static std::coroutine_handle worker(std::ifstream& fin) { while (true) { current->line = read_next_line(fin); if (current->line.empty()) co_return; co_yield; } } public: // 初始化协程 static AsyncLineReader create(const std::string& filename) { std::ifstream fin(filename); AsyncLineReader* self = new AsyncLineReader; current = self; self->coro = std::coroutine_handle ::from_promise(*(new promise_type)); std::thread t([self, fin = std::move(fin)]() mutable { auto h = worker(fin); h.resume(); // 开始协程 while (!h.done()) { h.resume(); } delete self; }); t.detach(); return *self; } }; “` ### 4. 使用示例 “`cpp int main() { auto reader = AsyncLineReader::create(“sample.txt”); std::string line; while (!(line = reader.next()).empty()) { std::cout

发表评论