📜  C / C++中的协程

📅  最后修改于: 2021-05-26 01:00:02             🧑  作者: Mango

什么是协程?
协程是一般的控制结构,其中流量控制在两个不同的例程之间协同传递而不返回。
如果您使用过Python或C#,您可能会知道有一个名为yield的关键字,它允许在调用者和被调用函数之间来回循环,直到调用者未使用函数完成或函数由于某种逻辑而终止为止。

样本Python3收益代码

# A Python program to generate numbers in a 
# range using yield
   
def rangeN(a, b):
    i = a
    while (i < b):
        yield i
        i += 1  # Next execution resumes 
                # from this point    
  
for i in rangeN(1, 5):
        print(i)

输出 :

1
2
3
4
5 

此代码演示了产量如何工作,并简要介绍了如何在调用方和被调用方之间更改控件。

为什么需要协程?
要读取文件并在读取一些有意义的数据时对其进行解析,可以在每一行中逐步读取文件,这很好。您还可以将全部内容加载到内存中,这在大型文本情况下(例如Microsoft Word之类的文本编辑器或在现代系统中仅使用Pipes的情况下,不建议这样做)。

在《计算机编程艺术》中,唐纳德·克努斯(Donald Knuth)为此类问题提供了解决方案。他的答案是完全放弃堆栈概念。停止将一个过程视为呼叫者,将另一个过程视为被呼叫者,并开始将它们视为协作平等。
因此,我们现在可以尝试看看如何在C语言中实现相同的目标。

function read():
   /* reads the content in the desired number 
      of steps and returns back control to parser
      but saves its own state of function. */

function parse():
   a = read()
   while (a)
   {
       // do something
       a = read()
   }

好吧,实际上,该结构看起来与C的调用方-被调用方结构非常相似。但是我们在这里需要的是读者必须记住其状态。它必须记住上一次完成任务的时间,并且还应该可以重新设置。

如何在C中实现协程?
挑战在于用C语言编写协程,C本身就是一种基于堆栈的语言,即在C语言中对函数调用的每次响应中,都有一个初始化的堆栈来跟踪其所有变量和常量,并在函数调用时被销毁结束。

int read(void) 
{
    int i;
    for (i = 0; i < 10; i++)
        return i;   /* Well on the first run itself 
                      the function will be destroyed */
}

我们需要做两件事:

  1. 将控制恢复到其最后状态
  2. 通过通话使数据持久化

以上两个问题均应通过使用静态变量来解决。但是如何记住状态并返回到与之前相同的执行状态,即返回或循环后的代码行。我们可以使用GOTO语句。一般不建议这样做。在这里,我们可以尝试一种叫做Duff的设备。

因此,我们终于可以继续使用解决方案代码了。

// C program to demonstrate how coroutines
// can be implemented in C.
#include
  
int range(int a, int b)
{
    static long long int i;
    static int state = 0;
    switch (state)
    {
    case 0: /* start of function */
        state = 1;
        for (i = a; i < b; i++)
        {
            return i;
  
        /* Returns control */
        case 1:; /* resume control straight
                    after the return */
        }
    }
    state = 0;
    return 0;
}
  
// Driver code
int main()
{
    int i; //For really large numbers
  
    for (; i=range(1, 5);)
        printf("control at main :%d\n", i);
  
    return 0;
} 

输出 :

control at range
control at main :1
control at range
control at main :2
control at range
control at main :3
control at range
control at main :4 

该解决方案利用了我们对Duff设备的理解,并使其发挥作用。现在,我们基本上可以在for循环中包含多个return语句,并且每次经过编程就可以返回不同的执行状态。此实现仅模仿Python的range函数,该函数也是基于协程的,因为它从Python3开始返回生成器对象。

来源 :
Simon Tatham在C中的协程

想要从精选的最佳视频中学习和练习问题,请查看《基础知识到高级C的C基础课程》。