专栏首页Jackie技术随笔C/C++协程的简单尝试
原创

C/C++协程的简单尝试

最近用tars框架编写后台服务的时候,逐渐抛弃了之前的异步调用方式,而是使用协程,以同步代码的写法实现并发调用,所以希望可以了解学习一下协程的相关知识。

Python中的yield

Python中有yield的关键词。例如定义一个函数:

def rangeN(a, b):
    i = a
    while(i < b):
        yield i
        i += 1

yeild将函数rangeN(a, b)变成一个generator类,调用它时,执行到yield i时,就返回i,下次迭代时,代码从yield i的下一行,即i += 1开始执行,且函数中的局部变量i保持了上次中断执行前的值。

测试一下它的效果:

for i in rangeN(1, 5):
    print(i)

输出:

1
2
3
4

尝试用C实现协程

难点在于C语言的函数调用是基于栈帧的,每次函数调用,都会初始化一个栈,来存放变量等,函数调用结束时这个栈便会被销毁。

例如下面这个程序:

int read(void) 
{ 
	int i; 
	for (i = 0; i < 10; i++) 
		return i; /* 很明显,根本运行不到10次,在第1次,这个函数就返回了 */
} 

void main(void)
{
    printf("i is %d\n", read());
}

输出:

i is 0

如果要实现协程,那么需要做到两点:

  1. 恢复的时候,能够从函数最后调用的地方继续执行
  2. 数据在一次函数调用结束后不会被销毁

其中第2点,可以使用静态变量保存的方式来实现。但是怎么记住状态,并且回来的时候从最后的状态继续执行?我们可以使用GOTO,但是,搜一下goto,google可以返回你100个不使用它的理由。

所以,尝试使用“Duff's device(达夫设备)”来实现:

#include<stdio.h> 
  
int range(int a, int b) 
{ 
    static long long int i; 
    static int state = 0; 
    printf("Function start,state :%d,i :%d\n", state, i);
    switch (state) 
    { 
    case 0: /* 函数入口 */
        state = 1; 
        for (i = a; i < b; i++) 
        { 
            return i; 
  
        /* 恢复执行 */
        case 1:printf("control at range :%d\n", i); /* 在return后恢复控制 */
        } 
    } 
    state = 0; 
    printf("Function end,state :%d,i :%d\n", state, i);
    return 0; 
} 
  
int main() 
{ 
    int i;
  
    for (; i=range(1, 5);) 
        printf("control at main :%d\n", i); 
  
    return 0; 
}  

输出:

Function start,state :0,i :0
control at main :1
Function start,state :1,i :1
control at range :1
control at main :2
Function start,state :1,i :2
control at range :2
control at main :3
Function start,state :1,i :3
control at range :3
control at main :4
Function start,state :1,i :4
control at range :4
Function end,state :0,i :5

Duff’s Device,达夫设备,是C中switch语句最巧妙的实现。

第二次调用range函数时,由于静态变量state的值已为1,所以程序直接跳过了为i赋值的12行for循环语句,执行17行的case语句。这样就进入了for循环的内部,使得循环结束后,自增值i从上次结束的值开始i++

反复执行上述过程,直到range中的for循环终止,返回0,那么main中的循环也随即终止,执行结束。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • VB 中chr(10)、chr(13)和vblf、vbcr、vbcrlf的分别

       cr是回车,只有回车,是到本行的最头上;lf是换行,到下一行;crlf是到下一行的最头上

    令仔很忙
  • “循环”左移

    #include<stdio.h> #include<stdlib.h> #include<math.h> int main(void) { int ...

    汐楓
  • 数组(更新...)

    在学习语言时,我们都会遇到数组.大学期间学过C,C++,Java,C#.这些语言中都学了数组,那时候用的不多,概念比较模糊,现在又学了php,里面也有数组,就打...

    仇诺伊
  • 迪杰斯特拉(dijkstra)c语言实现方法

    迪杰斯特拉(dijkstra)是用来实现查找一个点到其它点最短路径的一种方法。通过查找从起点到最短距离的点,然后将该点放入到集合中,代表以及找到起点到这一点的最...

    诸葛青云
  • c语言新手的无奈,几个新手容易犯的错误

    如果你是一个c语言新手,你很能试过在写代码的时候看上去明明问题,但是运行的时候就出现了错误。下面的错误你犯过几个?

    诸葛青云
  • c语言函数的隐式声明

    编译器只有碰到函数原型的时候才知道这个函数的名字,参数类型个数返回值,到函数调用的时候才知道如何生成指令,所以函数原型必须出现在函数调用之前。

    用户3094376
  • C语言什么是结构体?初步学习C语言结构体三部曲

    结构体部分内容,涉及结构体定义,结构体变量,结构体指针,结构体数组,更多内容敬请关注。

    诸葛青云
  • PHP HashTable总结

    本篇文章主要是对 PHP HashTable 总结,下面的参考链接是很好的学习资料。学习“散列”这个数据结构—推荐《数据结构与算法分析 C语言描述》

    大眼瞪小眼
  • 简述在C语言中, “字符”与“字符串”之间的区别

    在C语言中,“字符”与“字符串”之间,是有区别的。这一篇文章中,我们将介绍一下,在C语言中的“字符”与“字符串”,它们之间的区别。

    诸葛青云

扫码关注云+社区

领取腾讯云代金券