关闭

一种协程的 C/C++ 实现

发表于:2014-8-13 10:20

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:roxma    来源:51Testing软件测试网采编

  然后,我们需要一下全局的列表来保存这些 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
22/2<12
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号