协程基础
协程入门:用 ucontext 实现生产者和消费者
什么是协程
协程是一段可以暂停、随后继续执行的程序。普通函数通常在完成后返回;协程可以在执行到一半时让出控制权,之后从暂停的位置接着运行,局部变量和调用状态也会保留下来。
例如,生产者生成一个数据后暂停,让消费者处理;消费者处理完,再恢复生产者,生成下一个数据。两段代码交替执行,却不需要创建两个线程。
进程提供资源和地址空间,线程由操作系统调度,协程则在线程上运行,由程序或运行时安排切换。下面的例子只用一个线程,同一时刻只有一个协程在执行。
Windows 提供了类似的机制——Fiber(纤程)。可以用 ConvertThreadToFiber() 转换当前执行流,用 CreateFiber() 创建纤程,再通过 SwitchToFiber() 主动切换。Windows Fiber 文档
ucontext 的接口和结构体
ucontext 是 Unix 系统中的一组上下文操作接口,头文件为 <ucontext.h>。下面的代码以 Linux/glibc 为例;这些接口已从 POSIX.1-2008 移除,并非所有 Unix 平台都支持。
| 接口 | 作用 |
|---|---|
getcontext(&ctx) |
把当前执行上下文保存到 ctx |
makecontext(&ctx, func, argc, ...) |
设置上下文的入口函数及参数,激活时从 func 开始执行 |
swapcontext(&from, &to) |
保存当前上下文到 from,切换到 to;再次恢复 from 时从本次调用后继续 |
setcontext(&ctx) |
恢复 ctx,不保存当前上下文;成功时不沿原调用路径返回 |
ucontext_t 的主要字段如下:
| 字段 | 作用 |
|---|---|
uc_mcontext |
保存寄存器等机器状态,具体内容与平台有关 |
uc_stack.ss_sp |
协程栈内存区域的起始地址 |
uc_stack.ss_size |
栈内存区域的大小 |
uc_stack.ss_flags |
栈的标志,本例设为 0 |
uc_link |
入口函数正常返回后,要恢复的上下文 |
uc_sigmask |
运行该上下文时使用的信号屏蔽集合 |
创建上下文时,先调用 getcontext(),再分配栈并设置 uc_stack、uc_link,最后调用 makecontext()。makecontext() 只设置入口,不会立即执行函数。getcontext 文档、makecontext 文档
生产者消费者示例
这里用一个整数 buffer 存放数据。生产者依次写入 1~10,每写入一个就切换到消费者;消费者读取后切回生产者。因此,下一次写入之前,上一个数据已经被消费。
1 |
|
保存为 ucontext_demo.cpp,在 Linux/glibc 环境中编译运行:
1 | g++ -std=c++17 -Wall -Wextra ucontext_demo.cpp -o ucontext_demo |
预期输出如下,中间几组数据省略:
1 | [producer] produce: 1 |

每次调用 swapcontext(),当前函数都还没有结束。消费者循环中的 i 会保留,恢复后继续递增,不会重新从 0 开始。两个协程各自使用一块栈,切换时栈内存留在原处。
第 10 个数据消费完后,消费者仍切回生产者。生产者退出循环,通过 uc_link 回到 main;main 再恢复消费者,让它也退出循环。两边都结束后,才释放栈内存。
这个例子靠主动切换安排执行顺序。如果其中一方调用阻塞的 read() 或 sleep(),整个线程仍会等待,另一个协程不会自动接着运行。
对称协程与非对称协程
对称协程
对称协程可以直接把控制权交给指定协程。A 可以切换到 B,B 也可以切换到 A,切换目标由当前协程决定。
上面的生产者消费者就采用这种方式:生产者执行 swapcontext(&p_ctx, &c_ctx),消费者执行 swapcontext(&c_ctx, &p_ctx)。处理数据时,双方直接交替,不需要每次回到 main。
非对称协程
非对称协程通常使用 resume() 和 yield():调用者通过 resume() 恢复协程,协程通过 yield() 把控制权交回恢复它的调用者。
例如,消费者恢复生产者,生产者生成一个数据后让出,回到消费者;下次需要数据时,消费者再恢复生产者。生产者只需要执行 yield(),不必指定消费者的上下文。两种协程模式的说明

常见方案
- Boost.Coroutine2:提供有栈、非对称协程,常用于生成器和数据流。
- libco:C/C++ 有栈协程库,结合事件循环和部分 I/O Hook,支持用同步风格组织网络处理逻辑。
- Boost.Asio:异步 I/O 库,可以配合 C++20 的
co_await编写网络代码。
C++20 也提供了 co_await 等语言级协程支持,C++26对写成进行了完善。




