Open In App

Coroutines in C/C++

Last Updated : 17 May, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Coroutines are general control structures where flow control is cooperatively passed between two different routines without returning. 
If you have used Python or C#, you may know that there is a keyword called yield that allows a loop back and forth between the caller and the called function until the caller is not done with the function or the function terminates because of some logic it is given.

Sample Python3 code of yield. 

Python




# 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)


Output

1
2
3
4

This code demonstrates how the yield works and gives a brief idea about how the control is changed between the caller and callee. 

Why Coroutines are needed? 

To read a file and parse it while reading into some meaningful data, you can either read step by step at each line, which is fine. You may also load the entire content in memory, which won’t be recommended for large text cases e.g text editors like Microsoft Word or in modern systems just use Pipes. 

In The Art of Computer Programming, Donald Knuth presents a solution to this sort of problem. His answer is to throw away the stack concept completely. Stop thinking of one process as the caller and the other as the callee, and start thinking of them as cooperating equals. So we can now try and see how to achieve the same in 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()
   }

Well, in practice this structure looks very similar to the caller-callee structure of C. But what we require here is that the reader must remember its state. It must remember where it was last time when it did the job and should also be re-settable.

How to implement Coroutines in C? 

The challenge is to have coroutines in C language which is itself a stack-based language i.e in every response to a function call in C language there is a stack being initialized that keeps track of all its variables and constants and gets destroyed when the function call ends.
 

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 */
}


We need to do two things:  

  1. Resume control to its last state
  2. Make data persist through calls

Both of these above problems should be solved by the use of static variables. But how to remember the state and also return back to the same execution state as before i.e., the lines of code after the return or the loop. We can use GOTO statements. Which is not recommended generally. Here, we can try something called Duff’s device. So we finally move on to the solution code.

C++




// C++ program to demonstrate how coroutines
// can be implemented in C++.
#include <iostream>
using namespace std;
 
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:
            cout << "control at range"
                 << endl; /* 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);)
        cout << "control at main :" << i << endl;
 
    return 0;
}


C




// C program to demonstrate how coroutines
// can be implemented in C.
#include<stdio.h>
 
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;
}


Output

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
control at range

The solution uses our understanding of Duff’s device and has it play with it. We can now essentially have multiple return statements inside the for loop and each time we return to a different state of execution if it’s programmed to do so. This implementation only mimics the range function of python which is also based on coroutine since it returns generator objects as of Python3.

Source: Coroutines in C by Simon Tatham

 



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments