« Previous entry | Next entry » Browse > Snippets
Skip to comments (1)
Reentrant coroutines in C++
Posted by Erik on Jan 09 2006 @ 16:14 :: 3113 unique visits
My previous post Simple coroutines in C showed some macro's to turn normal C/C++ funtions into coroutines. A disadvantage of these coroutines was that they weren't reentrant. I have found two ways to fix this problem:- Adding an extra context parameter to the function. This would require some modification in the body of the function, e.g. context->i instead of i. It would also require the caller of the function to create and remember the context. An advantage is that this method works in both C and C++.
- Overloading the function application operator of a class and using the class as the context. This only works in C++ but requires minimal code modifications.
Here I will only discuss the second method because I find it a nicer way to solve the problem.
First thing is that the coroutine macro's need a little modification.
The cr_start macro is divided into 3 seperate macro's:
CODE: CPP
// old cr_start
#define cr_start() static int __s = 0; switch (__s) { case 0:
// new macro's
#define cr_context int __s;
#define cr_init() __s = 0;
#define cr_start() switch (__s) { case 0:
#define cr_return(x) { __s = __LINE__; return x; case __LINE__: ; }
#define cr_end() { break; default: for (;;) ; } } __s = 0;
#define cr_start() static int __s = 0; switch (__s) { case 0:
// new macro's
#define cr_context int __s;
#define cr_init() __s = 0;
#define cr_start() switch (__s) { case 0:
#define cr_return(x) { __s = __LINE__; return x; case __LINE__: ; }
#define cr_end() { break; default: for (;;) ; } } __s = 0;
Here is an example of the foobar() function from my previous post about coroutines as a reentrant coroutine:
CODE: CPP
class foobar_f {
private:
cr_context;
// place the variables which need to be remembered between calls here.
int i;
public:
foobar_f(void) {
cr_init();
}
// overloading the function application operator "()"
int operator () (void) {
cr_start();
for (i = 0; i < 1337; i++) {
cr_return(i);
}
cr_end();
}
};
private:
cr_context;
// place the variables which need to be remembered between calls here.
int i;
public:
foobar_f(void) {
cr_init();
}
// overloading the function application operator "()"
int operator () (void) {
cr_start();
for (i = 0; i < 1337; i++) {
cr_return(i);
}
cr_end();
}
};
The usage of the coroutine requires a little modification from the caller's side:
CODE: CPP
// create a function object, sometimes (incorrectly) called functor.
foobar_f foobar;
printf("%d\n", foobar()); // prints 0
printf("%d\n", foobar()); // prints 1
printf("%d\n", foobar()); // prints 2
foobar_f foobar;
printf("%d\n", foobar()); // prints 0
printf("%d\n", foobar()); // prints 1
printf("%d\n", foobar()); // prints 2
One important note I forgot in my previous post
You can't use a the cr_return macro inside the case of one of your own switch statements!
This because coroutines are implemented using a switch statement and cr_return uses a case statement of it's own.
1. On Aug 09 2008 @ 04:53 priya wrote:
Anyone bought from www.belrion.com before ? heard they are a paypal world seller and are macfee secured. Appreciate some feedback from anyone ^^<a href = http://www.belrion.com/en/ffxi.htm > buy ffxi</a><br>
<a href = http://www.belrion.com/en/eq.htm> buy eq flat </a><br>
<a href = http://www.belrion.com/en/wow.htm> cheap wow gold</a><br>
<a href = http://www.belrion.com> LOTR gold</a><br>
<a href = http://www.belrion.com/en/sell.htm>buy aoc gold</a><br>
<a href = http://www.belrion.com/en/l2.htm> buy L2 adena</a><br>
<a href = http://www.belrion.com/en/gamesvr.php?cid=1&gid=3&sid=10 >buy gils</a><br>
<a href = http://www.belrion.com/en/eq.htm >cheap gold wow</a><br>