基于Duff's Device的C简易无栈协程实现

参考 Simon Tatham 的文章https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

译文为https://mthli.xyz/coroutines-in-c/

协程是一组序列化的子过程,与线程不同,协程的调度是由用户而非操作系统执行的,协程可以在任意时刻让出CPU(称为yield操作),下次调用时从上次yield的地方继续执行

Simon Tatham利用Duff's Device实现了一种简易的无栈协程,示例代码如下:

int function(void) {
    static int i, state = 0;
    switch (state) {
        case 0: 
        for (i = 0; i < 10; i++) {
            state = 1; 
            return i;
            case 1:;
        }
    }
} 

该函数的作用是第i次调用时返回i,最多10次(相同的函数功能可以通过一个statci变量实现,但本文是为了讨论协程),其核心部分为switch语句以及return前后两句,通过设置不同的state来保证下一次调用时从上次退出的地方继续执行(如果不明白switch为何能和for套在一起写可以自行搜索Duff's Device)

可以看出,每次调用return时设置的state必须不同,可以利用__LINE__宏来设置state,这样只要不在一行调用两次return即可

以下是将其用宏封装的代码

#include <stdio.h>

#define crBegin static int state = 0; switch (state) { case 0:
#define crReturn(x) do { state = __LINE__; return x; case __LINE__:; } while (0)
#define crFinish }

void f1() {
    crBegin;
    puts("1");
    puts("2");
    crReturn();
    puts("3");
    crFinish;
}

void f2() {
    crBegin;
    puts("x");
    crReturn();
    puts("y");
    puts("z");
    crFinish;
}

int main (void) {
    f1();
    f2();
    f1();
    f2();
    return 0;
} 

do while(0)是为了让crReturn与if else嵌套时不用考虑大括号问题

这份代码运行后会依次输出1,2,x,3,y,z

至此,一份用C实现的简易无栈协程就完成了,需要注意的是,因为switch内部不能任意定义变量,请在crBegin之前定义所需变量

PS:这份代码仅供学习参考,如果你在实际生产代码中用了可能会被上司打死

posted @ 2020-10-22 20:15  图斯卡蓝瑟  阅读(718)  评论(0)    收藏  举报