然后,我们需要一下全局的列表来保存这些 RoutineInfo 对象。
std::list<RoutineInfo*> InitRoutines(){
std::list<RoutineInfo*> list;
RoutineInfo *main = new RoutineInfo(0);
list.push_back(main);
return list;
}
std::list<RoutineInfo*> routines = InitRoutines();
接下来是协程的创建,注意当协程的时候,程序栈有可能已经被损坏了,所以需要一个 stackBack 作为程序栈的备份,用来做后面的恢复。
void *stackBackup = NULL; void *CoroutineStart(void *pRoutineInfo); int CreateCoroutine(RoutineHandler handler,void* param ){ RoutineInfo* info = new RoutineInfo(PTHREAD_STACK_MIN+ 0x4000); info->param = param; info->handler = handler; pthread_t thread; int ret = pthread_create( &thread, &(info->attr), CoroutineStart, info); void* status; pthread_join(thread,&status); memcpy(info->stackbase,stackBackup,info->stacksize); // restore the stack routines.push_back(info); // add the routine to the end of the list return 0; } |
然后是 CoroutinneStart 函数。当线程进入这个函数的时候,使用 setjmp 保存上下文,然后备份它自己的程序栈,然后直接退出线程。
void Switch(); void *CoroutineStart(void *pRoutineInfo){ RoutineInfo& info = *(RoutineInfo*)pRoutineInfo; if( !setjmp(info.buf)){ // back up the stack, and then exit stackBackup = realloc(stackBackup,info.stacksize); memcpy(stackBackup,info.stackbase, info.stacksize); pthread_exit(NULL); return (void*)0; } info.ret = info.handler(info.param); info.stopped = true; Switch(); // never return return (void*)0; // suppress compiler warning } |
上下文切换
一个协程主动调用 Switch() 函数,才切换到另一个协程。
std::list<RoutineInfo*> stoppedRoutines = std::list<RoutineInfo*>(); void Switch(){ RoutineInfo* current = routines.front(); routines.pop_front(); if(current->stopped){ // The stack is stored in the RoutineInfo object, // delete the object later, now know stoppedRoutines.push_back(current); longjmp( (*routines.begin())->buf ,1); } routines.push_back(current); // adjust the routines to the end of list if( !setjmp(current->buf) ){ longjmp( (*routines.begin())->buf ,1); } if(stoppedRoutines.size()){ delete stoppedRoutines.front(); stoppedRoutines.pop_front(); } } |
演示
用户的代码很简单,就像使用一个线程库一样,一个协程主动调用 Switch() 函数主动让出 CPU 时间给另一个协程。
#include <iostream> using namespace std; #include <sys/wait.h> void* foo(void*){ for(int i=0; i<2; ++i){ cout<<"foo: "<<i<<endl; sleep(1); Switch(); } } int main(){ CreateCoroutine(foo,NULL); for(int i=0; i<6; ++i){ cout<<"main: "<<i<<endl; sleep(1); Switch(); } } |
记得在链接的时候加上 -lpthread 链接选项。程序的执行结果如下所示:
[roxma@VM_6_207_centos coroutine]$ g++ coroutime_demonstration.cpp -lpthread -o a.out [roxma@VM_6_207_centos coroutine]$ ls a.out coroutime.cpp coroutime_demonstration.cpp README.md [roxma@VM_6_207_centos coroutine]$ ./a.out main: 0 foo: 0 main: 1 foo: 1 main: 2 main: 3 main: 4 main: 5 |