企业网站404页面设计,绵阳哪个网站做外卖做的好,APP网站建设什么用处,站长工具在线免费coroutine一般翻译过来就是协程#xff0c;类似于线程可以切换#xff0c;而跟线程是由操作系统调度器来实现切换不一样#xff0c;协程由用户程序自己调度进行切换。我以前也看过协程相关的内容#xff0c;但没有自己去实现过。最近搞OpenStack#xff0c;OpenStack各个模… coroutine一般翻译过来就是协程类似于线程可以切换而跟线程是由操作系统调度器来实现切换不一样协程由用户程序自己调度进行切换。我以前也看过协程相关的内容但没有自己去实现过。最近搞OpenStackOpenStack各个模块都是单线程模型但是用了eventlet的绿色线程eventlet也是Python的协程实现库。这篇文章我并不打算剖析Python协程库的实现而是分析一个基于Linux下ucontext组件的C语言实现原作者是云风我以前也看过这个实现只是现在忘了没有自己写过或者分析过代码只是看看好像永远是似懂非懂。后来yanyiwu又fork了一个实现并做些修改据说更易懂我就直接拿他修改后的版本分析就ok了这里对他们表示感谢。 这个简单的实现包含三个文件分别是头文件coroutine.h协程实现文件coroutine.c和测试主程序main.c我给代码加了点注释并编译运行。 coroutine.h源码 coroutine.h里面是一些宏定义和函数声明 coroutine_func一个函数指针声明了coroutine的函数原型 coroutine_open要使用该协程库时第一个被调用的函数它返回一个调度器结构体 coroutine_close关闭协程调度器最后被调用不解释 coroutine_new将一个函数还有需要传递的参数加入到协程的调度器里边 coroutine_yield退出当前运行的协程 coroutine_resume恢复具有特定id值的协程 coroutine_running返回正在运行的协程id-1表示没有正在运行的协程 schedule_status返回1表示还有等待运行的协程返回0表示所有协程都已运行完毕 主要的实现都在coroutine.c文件源码如下 对coroutine.c源码我们暂时不作分析一会儿分析main.c时自然会讲到它。 main.c源码如下 我们来分析下main.c的代码。先看下main函数调用了coroutine_open函数返回一个调度器结构体然后调用test函数并把调度器结构体当作参数最后调用coroutine_close函数关闭调度器。显然test函数就是接脏活累活的地方了。看下test函数里的3536行调用了coroutine_new创建两个协程分别使用了函数foo和foo2参数分别为arg1和arg2并返回了协程id分别为co1和co2。接着是一个while循环看下代码 while (schedule_status(S)) { coroutine_resume(S,co1); coroutine_resume(S,co2); } 可以看出当schedule_status返回为1时将对协程co1和co2分别调用 coroutine_resume函数schedule_status返回0时test函数退出。这回我们不得不去看coroutine_resume函数了 coroutine_resume函数有两个参数分别为调度器结构体和协程id。该函数首先根据协程id从调度器中获取对应的协程结构体然后对状态status作判断可能的状态为COROUTINE_READY和COROUTINE_SUSPEND。 status为COROUTINE_READY(协程第一次被调度)时 调用getcontext获取当前(注意当前不是传进来id所对应的协程)协程的上下文保存在传进来的id所对应的协程结构体中类型为ucontext_t的变量ctx接着修改ctx结构体的栈指针和栈大小并把该协程退出时要执行的协程上下文设置成调度器结构体内类型为ucontext_t的变量main然后将调度器结构体里running变量设置为要将要执行的协程的id将要执行的协程的状态status设置为COROUTINE_RUNNING再调用makecontext修改要执行协程上下文参数为要执行的协程上下文变量、mainfunc函数地址、mainfunc参数个数、给mainfunc传递的参数因此后续该协程执行时就会调用mainfunc函数最后调用swapcontext该函数将当前协程的上下文内容保存在调度器结构体的main变量中并激活要执行的协程上下文于是mainfunc函数被调用了。 status为COROUTINE_SUSPEND时 将调度器结构体里的变量running设置成传进来的参数id将该id对应的协程状态status设置成COROUTINE_RUNNING调用swapcontext保存当前协程上下文激活执行参数id对应的协程。当协程为这个状态时肯定是曾经被调度过了即经历过了COROUTINE_READY阶段其栈指针已经被修改过因此不需要再次修改而直接激活执行。 不难看出每个协程第一次被调度时都调用了makecontext函数并把mainfunc函数设置成该协程执行时就去调用的函数因此我们知道协程co1和co2所对应函数foo和foo2都是在mainfunc中被调用。我们再看下foo和foo2的实现 这两个函数中都有一个for循环每循环一次就调用coroutine_yield函数该函数首先将当前协程的状态status改为COROUTINE_SUSPEND将调度器结构体里running变量设置为-1再调用swapcontext将协程上下文保存在当前协程的结构体变量ctx中激活调度器结构体里main变量对应的协程上下文这里实际上是切换到了主协程。 说到这里估计有些同学还是不明不白的我根据自己的理解具体来解释一下流程 while循环里边对协程co1调用coroutine_resume时由于第一次调用进入COROUTINE_READY分支这时候getcontext获取主协程(不知道描述对不对)的上下文然后修改栈后作为协程上下文保存在co1对于的协程结构体中然后mainfunc中执行co1对于的函数foo在foo中调用了coroutine_yield这时co1被设置成COROUTINE_SUSPEND切换到刚才保存的主协程中这是test函数里边的coroutine_resume又被调用不过这时是对co2同样的命运co2对应的foo2被调度执行没想到foo2函数也自动将自己设置成COROUTINE_SUSPEND这时又切换到了主协程中test中又一次循环开始coroutine_resume对co1调用只是这次进入COROUTINE_SUSPEND分支这回不用设置什么栈了直接换成执行协程co1对co2也一样不再赘述。 那么问题又来了co1和co2什么时候彻底结束、主程序得以退出呢 foo和foo2中的for循环次数是有限的当循环条件不满足时coroutine_yield函数不会被调用这时mainfunc中的调用“C-func(S, C-arg); ”结束之后的语句“C-status COROUTINE_DEAD;”被调用将对应的协程状态status设置为COROUTINE_DEAD。当两个协程状态都为COROUTINE_DEAD时schedule_status函数返回0主协程中的while循环退出主程序就退出了。再看下程序的执行结果一切都变得明了了。 运行结果 转载于:https://www.cnblogs.com/woshiweige/p/4518428.html