本篇使用上一篇提供的接口,实现一个简单的协程调度框架.
基本思想是,创建一个调度器,用于将处于活动状态的协程调度运行,调度器维护着一个actived列表,
调用spawn创建协程时,将新建立的协程添加到活动列表中。
调用schedule将启动调度器主循环.
coro.h
#ifndef _CORO_H #define _CORO_H #include <stdint.h> #include "uthread.h" struct coro { struct coro *next; uthread_t ut; uint32_t id; start_fun st_fun; uint32_t is_end; }; struct testarg { struct coro *sche; struct coro *co; }; void* yield(struct coro*,struct coro*,void *); void* resume(struct coro*,struct coro*,void *); struct scheduler { struct coro *active; //处于激活态的coro struct coro *self; }; struct scheduler *scheduler_create(); //生成一个coro运行start_run void spawn(struct scheduler*,void *stack,uint32_t stack_size,start_fun); //调度coro运行 void schedule(struct scheduler*); #endif
coro.c
#include "coro.h" #include <stdlib.h> #include <time.h> void* yield(struct coro *from,struct coro *to,void *arg) { return uthread_swtch(from->ut,to->ut,arg); } void* resume(struct coro *from,struct coro *to,void *arg) { return uthread_swtch(from->ut,to->ut,arg); } static uint32_t g_index = 0; static void* coro_start_fun(void *arg) { struct testarg *_arg = (struct testarg *)arg; void *ret = _arg->co->st_fun(_arg); _arg->co->is_end = 1; return ret; } void spawn(struct scheduler *sche,void *stack,uint32_t stack_size,start_fun st_fun) { uthread_t ut = uthread_create(stack,stack_size); struct coro *co = (struct coro*)malloc(sizeof(*co)); co->ut = ut; co->st_fun = st_fun; co->id = ++g_index; //添加到激活队列中 co->next = sche->active; co->is_end = 0; sche->active = co; uthread_make(co->ut,sche->self->ut,coro_start_fun); } struct scheduler *scheduler_create() { struct scheduler *sche = (struct scheduler *)malloc(sizeof(*sche)); sche->active = 0; sche->self = (struct coro*)malloc(sizeof(*sche->self)); sche->self->ut = uthread_create(0,0); return sche; } void schedule(struct scheduler *sche) { while(1) { if(sche->active) { struct coro *cur = sche->active; sche->active = 0; while(cur) { struct testarg arg = {sche->self,cur}; resume(sche->self,cur,&arg); struct coro *tmp = cur->next; if(!cur->is_end) { cur->next = sche->active; sche->active = cur; cur = tmp; } else { uthread_destroy(&(cur->ut)); free(cur); } cur = tmp; } } else break; } }
test.c
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include "uthread.h" #include "coro.h" void* fun(void *arg) { struct testarg *_arg = (struct testarg *)arg; int i = 0; while(i<10) { printf("%d\n",_arg->co->id); yield(_arg->co,_arg->sche,0); ++i; } return 0; } int main() { struct scheduler *sche = scheduler_create(); spawn(sche,malloc(4096),4096,fun); spawn(sche,malloc(4096),4096,fun); spawn(sche,malloc(4096),4096,fun); spawn(sche,malloc(4096),4096,fun); schedule(sche); return 0; }