现在的位置: 首页 > 综合 > 正文

简单协程

2013年02月20日 ⁄ 综合 ⁄ 共 1471字 ⁄ 字号 评论关闭

/*
协程最复杂的地方是:
如果在协程切换的时候,某些函数只执行到中途,则需要保留栈数据.
这样将涉及到栈切换的操作.
考虑一种简单情况,即只在协程函数执行切换,则可以用return来做,这样:
所有协程函数保证在切换的时候,其栈为空(因为是正常return),
则可以很容易实现.
这样本质上就等效于一个循环中的switch.

当协程函数切换的时候,实际就是return, 并通过返回的参数来确定:
(1)协程执行完毕
(2)切换回主调度协程
(3)切换到指定协程
这样,当协程启动的时候和暂停恢复的时候,都直接调用函数入口,
协程函数根据保存的上下文确定是初次执行还是从某处继续执行,
这里本质上也是一个switch或者goto.

那么这些上下文既然不能存在于栈里,保存在哪里呢?
根据需要有多种选择:
(1)保存在某个全局变量或者静态变量里
(2)作为返回值让调度程序保存, 然后作为参数传给协程函数
   由于返回值还需要指示协程切换,因而需要用结构体做返回值
(3)协程不是用函数,而是用函数对象,保存在成员变量里.

*/

// 显示数字 1~5

struct uthread
{
virtual int fun() = 0;
};

struct ThreadCreate : public uthread
{
ThreadCreate(int* outD)
{
step = 0;
outData = outD;
}
virtual int fun()
{
printf("Switch to ThreadCreate\n");
if(step >= 5)
{
// 结束
return -2;
}

if(*outData == 0)
{
++step;
*outData = step;
}
return 1;
// 启动ThreadPrint
}

int step;
// 控制执行到哪里了
int* outData;
// 数据通道
};

struct ThreadPrint : public uthread
{
ThreadPrint(int* getD)
{
step = 0;
getData = getD;
}
virtual int fun()
{
printf("Switch to ThreadPrint\n");
if(step >= 5)
{
// 结束
return -2;
}

if(*getData != 0)
{
++step;
printf("Data=%d\n", *getData);
*getData = 0;
}
return 0;
// 启动ThreadCreate
}
int step;
int* getData;
};

void uthread_mgr()
{
int chann = 0;
ThreadCreate ct(&chann);
ThreadPrint pt(&chann);

uthread* p[2] = {&ct, &pt};
bool bRun[2] = {true, true};
int index = 0;
while(index>=-1)
{
if(index == -1)
{
// 选第一个未结束的
for(int i=0; i<2; i++)
{
if(bRun[i])
{
index = i;
break;
}
}
if(index == -1)
{
// 全部结束了
break;
}
}
else 
{
if(bRun[index])
{
int new_index = p[index]->fun();
if(new_index == -2)
{
// 结束
bRun[index] = false;
index = -1;
}
else
{
index = new_index;
}
}
else
{
index = -1;
}
}
}

printf("==== End ====%d\n");
}

int _tmain(int argc, _TCHAR* argv[])
{
uthread_mgr();

return 0;
}

抱歉!评论已关闭.