协程
C++ 基于汇编实现的协程与 ucontext_t 版本有以下几个区别:
- 基于汇编实现的协程可以直接操作函数的上下文,而 ucontext_t 版本需要通过库函数来获取和设置上下文(1)(2)。
- 基于汇编实现的协程可以更精确地控制栈空间的分配和释放,而 ucontext_t 版本需要依赖系统提供的栈空间(1)(3)。
- 基于汇编实现的协程可以更好地适应不同的平台和编译器,而 ucontext_t 版本可能存在兼容性问题,因为 ucontext 库已被标记为过时(2)(3)。
根据网上的一些资料,ucontext.h 是 GNU C 库的一个头文件,主要用于用户态下的上下文切换。但是由于 makecontext 中设计的一些问题,该文件已经被标记为过时的(1)。一些可能的原因是:
有栈协程和无栈协程?
- 有栈协程:通过保存运行时的堆栈及运行时的上下文来保存运行状态,需要改变调用栈。
- 无栈协程:通过闭包或者状态机的方法记录程序的运行状态,不改变调用栈。
- 对称协程:各协程之间可以进行执行权的切换。
- 非对称协程:有一个中心化的调度器,所有协程都只和调度器进行执行权的切换。
有栈协程的实现方式?
- 使用 C 标准函数库的 setjmp 和 longjmp 函数
- 使用 POSIX 标准中的 ucontext 库,但是这个库已被标记为 obsolete
- 使用汇编直接对函数上下文进行操作
有哪些三方的协程库?libco?
- libco 是微信后台大规模使用的 c/c++ 协程库,它支持同步或者异步的写法,也提供了 socket 族函数的 hook,使得后台逻辑服务几乎不用修改逻辑代码就可以完成异步化改造(1)。
- libco 使用共享栈模式来实现协程,即每个线程只有一个栈空间,所有该线程上的协程都共享这个栈空间。这样可以节省内存空间,也可以支持更多的协程(2)。
- libco 使用汇编代码来实现上下文切换,即保存和恢复寄存器和栈指针。libco 支持 x86、x64、arm、arm64 等多种平台(3)。
- libco 提供了几个函数接口来创建、恢复和暂停协程。其中 co_create 用于创建一个新的协程;co_resume 用于恢复一个已经暂停的协程;co_yield 用于暂停当前运行的协程;co_poll 用于等待事件发生并调度相应的协程(4)。
C++20 / C++23 的协程了解吗?
- C++20 中的协程是非对称的、一等对象、无栈的。非对称意味着有一个中心化的调度器来控制协程之间的转移;一等对象意味着协程可以作为函数参数或返回值;无栈意味着每个协程不需要分配一个固定大小的栈空间。
- C++20 中使用 co_await、co_yield 和 co_return 关键字来标记协程暂停点和恢复点。co_await 用于等待一个异步操作完成;co_yield 用于生成一个值并暂停;co_return 用于返回一个值并结束。
- C++23 可能会提供更高层次的库来支持协程,比如 generator、task、future 等。这样就可以直接使用协程而不需要自己实现底层细节。
- 基于 ucontext_t 实现协程的具体原理?