1. 引言:为什么需要协程?
在现代编程中,我们经常需要处理异步操作。传统的多线程模型虽然强大,但存在一些问题:
- 线程创建和切换开销大
- 多线程编程复杂,容易出错(竞态条件、死锁等)
- 代码结构混乱,回调地狱
协程(Coroutine)是一种轻量级的并发模型,它允许在单个线程中暂停和恢复执行,避免了多线程的开销。协程的出现,让异步编程变得简单、清晰。
想象一下,你在点外卖:你下单后,不需要一直等着,可以去做其他事情(比如工作、学习)。当外卖到了,系统会通知你(恢复协程)。这就是协程的工作方式:在等待 I/O 操作时,协程可以暂停执行,让出 CPU 给其他任务;当 I/O 操作完成时,协程可以恢复执行。
2. 协程基础:协程与线程的区别
| 特性 | 线程 | 协程 |
|---|---|---|
| 创建成本 | 高(需要操作系统支持) | 低(在用户空间实现) |
| 切换成本 | 高(需要上下文切换) | 低(仅需保存/恢复栈指针) |
| 并发模型 | 硬件级并发 | 软件级并发 |
| 代码结构 | 复杂(回调地狱) | 简单(顺序执行) |
协程就像是一个"可以暂停的函数",它可以在执行过程中暂停(co_await),然后在适当的时候恢复执行。
3. 协程的内部机制:深入 promise_type
C++ 协程的核心是 promise_type,它定义了协程的生命周期和行为。让我们逐个分析 promise_type 中的各个方法:
3.1 promise_type():构造函数
promise_type(){ std::cout << "1.create promise object\n";}
当协程被创建时,promise_type 的构造函数首先被调用。这是协程初始化的开始。
3.2 get_return_object()
task get_return_object(){ std::cout << "2.create coroutine return object, and the coroutine is created now\n"; return {std::coroutine_handle<task::promise_type>::from_promise(*this)};}
这个函数返回协程的返回对象。当协程被创建时,这个函数被调用,返回一个 coroutine_handle,它代表了协程的执行句柄。
3.3 initial_suspend()
std::suspend_never initial_suspend(){ std::cout << "3.do you want to suspend the current coroutine?\n"; std::cout << "4.don't suspend because return std::suspend_never, so continue to execute coroutine body\n"; {};}

