C语言中的协程

引自:http://www.oschina.net/translate/coroutines-in-c

在《计算机程序设计艺术》中,Donald Knuth提供了一个解决这类问题的方法。他的方法是彻底丢掉堆栈的概念,不要再想一个进程作为调用者,另一个作为被调用者,把他们当做平等的协作者关系。

实际上就是:把传统的“调用”稍微改为一个不同的方式。新的“调用”将在某个地方保存返回值而不是堆栈上,并且还能跳转到另一个保存返回值的指定位置上。因此,解码器每次生成一个字符,就保存它的程序计数器并且跳转到上次解析器的位置-解析器每次都需要一个新的字符,它保存自己的程序计数器并且跳转到上次解码器的位置。程序可以在两个函数之间来回自如的传递需要的数据了。

理论上看起来很美,但实际中你却只能在汇编语言中使用,因为通用的高级语言没有一个支持调用原始的协程。像类似于C的都是依赖于基础的堆栈结构,因此当在函数间进行数据传递时,一个必须作为调用者,领一个必须作为被调用者。所以如果你想写可移植的代码,这种技术和Unix管道一样不切实际。

int fuction(void)
{
  static int i, state=0;
  switch(state){
    case 0: goto LABEL0;
    case 1: goto LABEL1;
  }
  LABEL0:
  for(i=0; i<10; i++)
  {
    state = 1;
    return i;
  LABEL1:;
  }
}
更进一步:
 
 
int function(void)
{
  static int i, state=0;
  switch(state){
  case 0:
    for(i=0; i<10; i++){
      state = 1;
      retrn i;
  case 1:;
    }
  }
}
更进一步
 
 
#define crBegin static int state=0; switch(state){case 0:
#define crReturn(i,x) do(state=i; return x; case i:;)while(0)
#define crFinish }
int function(void)
{
  static int i;
  crBegin;
  for(i=0; i<10; i++)
    crReturn(1,i);
  crFinish;
}

剩下的唯一问题是传给crReturn的第一个参数。就像在上一节引进一个新标签一样,我们必须避免与已存在的标签名冲突,确保所有给crReturn的状态参数都是不同的。这影响是相当小的 -- 编译器会抓住它并并不让它在运行时出错 -- 但我们还是要避免这样做。

虽然这可以解决,ANSI C还是提供了扩展到当前行号的专门的宏名:__LINE__,因此我们可以把crReturn重写成:

 
 
#define crReturn(x) do(state=__LINE__; return x;\
case:__LINE__;)while(0)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值