基于ucontext_t实现的非对称协程,本章对应源码:zhongluqiang/sylar-from-scratch at 4419dbda8cf40d9b9d3bb0b0b14242a4d1b8aa2c

协程概述


ucontext_t接口


sylar协程模块设计


sylar协程模块实现


注意事项


建议初学协程里,不要尝试深入x86/x64体系和汇编语言,只需要了解协程是什么,协程上下文和协程切换是怎么回事即可。


非对称协程,每个线程的入口函数作为主协程,其他协程为子协程,协程只能在主协程和子协程之间进行切换,不能在子协程与子协程之间切换。所对,这个协程模块最大的一点限制是,子协程不能创建并运行子协程,所有的协程都只能由主协程进行创建并调用。这个限制在引入调度器后可以通过调度器接口来规避掉,在使用调度器时,协程可以通过向调度器添加调度任务的方式来启动新的协程。

在非对称协程的实现中,每个线程永远只关心两个协程(由线程局部变量记录),一个是线程主函数的协程,另一个是子协程,在任意时间,要么主协程在前台运行、子协程在后台等待,要么子协程在前台运行、主协程在后台等待,绝对不会出现在前台运行和后台等待的协程都是子协程的情况。


协程:用户态的线程,相当于线程中的线程,更轻量级。后续配置socket hook,可以把复杂的异步调用,封装成同步操作。降低业务逻辑的编写复杂度。 目前该协程是基于ucontext_t来实现的,后续将支持采用boost.context里面的fcontext_t的方式实现。

协程原语:

`resume`:恢复,使协程进入执行状态  
`yield`: 让出,协程让出执行权

yield和resume是同步的,也就是,一个协程的resume必然对应另一个协程的yield,反之亦然,并且,一条线程同一时间只能有一个协程是执行状态。


协程关键:

1. 协程虽然被称为轻量级线程,但在同一个线程内,协程并不能并发执行,而是只能按顺序执行。其实这点也好理解,毕竟协程其实就是以一种花里胡哨的方式调用子函数,不管实现得如何巧妙,也不可能在单线程里做到同时运行两个子函数,否则还要多线程有何用?

2. 因为单线程下协程并不是并发执行,而是顺序执行的,所以不要在协程里使用线程级别的锁来做同步,比如pthread_mutex_t。如果一个协程在持有锁之后让出执行,那同线程的其他任何协程只要一旦尝试再次持有这个锁,整个线程就锁死了,这和单线程环境下,连续两次持有同一个锁导致的死锁原理完全一样。