Coroutine의 구성요소
coroutine executes synchronously with other coroutines!
i.e. we are not doing concurrency yet
in this case, a single thread is jumping back and forth between routines but with multiple stacks
There is two types of coroutines
1. semi-coroutine
2. full-coroutine
a fibonacci function that generates nth fibonacci number on nth call - with no paramater
Coroutine is like a class
** NEED TO BE COMPILED WITH u++
_Coroutine Fibonacci{
int fn; // communication variable
void main(){
int fn1, fn2;
fn = 0; fn1 = fn;
suspend(); // return to last resume
fn = 1; fn2 = fn1; fn1 = fn;
suspend(); // return to last resume
for(;;){
fn = fn1 + fn2; fn2 = fn1; fn1 = fn;
suspend(); // return to last resume
}
}
public:
int operator()(){ // functor
resume(); // transfer to last suspend
return fn;
}
}
Public routine is like an interface routine that protects inside mechanism from outside.
We can create multiple instances of coroutine because its a class!
Usage:
int main(){
Fibonacci f1, f2; // multiple instances
for(int i = 1; i <= 10; i++){
cout << f1() << " " << f2() << endl;
}
}
The reason why ()() functor is not in the stacks of coroutine is because the coroutine has not resumed yet
resume and suspend is a context switch not a call and return so coroutine only remembers last suspend and last resume.
the stacks of coroutine is created on first resume (cocall)
Just like any other object, coroutine is also object and it is destructed from stack once it is off the scope. The stack in coroutine also gets unwind and destructors of any objects in that stacks also gets properly called
* do not use catch(...) in coroutine. this will catch cleanup exception which is used to force stack unwinding on destruction
input:
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
output:
abcd efgh ijkl mnop qrst
uvwx yzab cdef ghij klmn
opqr stuv wxyz
without coroutine:
int main(){
int g,b;
char ch;
cin >> noskipws; // turn off white space skipping
for(;;){
for (g = 0; g < 5; g++){
for(b = 0; b < 4; b++){
for(;;){ // this is to ignore newline char and eof
cin >> ch; // read 1 char
if (cin.fail()) goto fini; // on eof, do multi level exit
if (ch != '\n') break; // ignore newline
}
cout << ch; // print char
}
cout << " "; // print block separator
}
cout << endl; // print group separator
}
fini: ;
if(g != 0 || b != 0) cout << endl;
}
with coroutine:
_Coroutine Format{
int g,b;
char ch;
void main(){
for(;;){
for (g = 0; g < 5; g++){
for(b = 0; b < 4; b++){
for(;;){ // this is to ignore newline char and eof
**suspend();**
if (ch != '\n') break; // ignore newline
}
cout << ch; // print char
}
cout << " "; // print block separator
}
cout << endl; // print group separator
}
}
public:
Format() {**resume();**} // start coroutine
~Format() {if( g != 0 || b != 0 ) cout << endl;}
void ptr(char ch) {Format::ch = ch; **resume();**}
}
usage:
int main(){
Format fmt;
char ch;
cin >> noskipws;
for(;;){
cin >> ch;
if(cin.fail()) break;
fmt.prt(ch);
}
}
tips
every coroutine inharites from uBaseCoroutine
_Coroutine uBaseCoroutine{
protected:
void resume(); //context switch to this
void suspend(); //context switch to last resumer
public:
uBaseCoroutine();
uBaseCoroutine(unsigned int stackSize); // get stack size
void verify(); // check stack
const char * setName(const char * name);// printed in error message
const char * getName() const;
uBaseCoroutine & starter() const; // coroutine performing first resume
uBaseCoroutine & resumer() const; // coroutine performing last resume
}