linux下纯C实现协程(借助setjmp/longjmp)
1.如何理解协程(coroutine)
首先,协程是在单个线程下讨论的概念;
何谓协程,就是满足如下定义:
- 可以随时“挂起”
- 之后可以回到“挂起”的状态继续执行
Python中的yield产生器很好地解释了协程的原理,它可以产生所有自然数;
重要的是,它不必每次从头开始生成,利用next()可以记住上次生成到了哪个数,它是有“记忆的”
def generate_int():
i = 0
while 1:
yield i
i += 1
下面是运行结果:
>> x = generate_int()
>> x
<generator object f at 0x7fb914988e08>
>> next(x)
0
>> next(x)
1
2. 如何实现协程
因为函数调用会临时维护一个函数桢栈,一旦调用完毕,这个桢栈都会被摧毁; 所以关键在于,在函数的一次调用完毕时,记录下当时的"函数上下文"。
2.0 为何不适用GOTO
GOTO只能实现函数内的切换,而不能实现函数间的切换;
2.1 调用setjmp库
C中<setjmp.h>提供的setjmp和longjmp提供了这种方法;
int setjmp(jmp_buf env)
若直接调用则返回0,若从longjmp调用返回则返回非0值的longjmp中的val值
void longjmp(jmp_buf env, int val)
调用此函数则返回到最近的setjmp所在的地方,其中env就是setjmp中的 env,而val 则是使setjmp的返回值变为val。
2.2 实现一个简单协程
下面尝试实现这样一个功能:
在不修改某些变量的前提下,满足Condition执行完A后,仍然回来执行B;
if ( Condition )
{ block A };
else
{ block B };
#include <setjmp.h>
#include <stdio.h>
jmp_buf env;
void A(){
printf("Now A\n");
longjmp(env,1); //这里跳回到if中继续执行
}
void B(){
printf("Now B\n");
}
int main()
{
if (!setjmp(env)) //setjmp初次返回0,第二次回来返回的就是1
A();
else
B();
return 1;
}
>> 执行结果:
Now A
Now B