« Previous entry | Next entry » Browse > Snippets

Skip to comments (9) Reentrant coroutines in C++
Posted by Erik on Jan 09 2006 @ 16:14  :: 4588 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:
  1. 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++.
  1. 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;
 


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();
    }
};


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
 


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.

9 comments posted so far
Add your own »

1. On Jan 21 2009 @ 06:06 mike wrote:

One downside of using __LINE__ is that the numbers will typically be very large, and this has implications for how efficiently the switch is compiled.  If the case values are small integers, then typically the compiler will render the switch as a jump to something indicated in an address table it generates, which executes faster than rendering it as a bunch of if statements.  even if the numbers are small enough to cause it to compile this way, the larger they are, the more space is wasted on this table (not a big deal, maybe).

The point is, in all major C++ compilers you can use the macro __COUNTER__, which expands to an integer which is one larger than the last time it expanded.

Generally I love this coroutine implementation, though.  It's the best of all the ones I've seen.

2. On Jan 21 2009 @ 06:24 mike wrote:

oh, this is trickier than I thought.  if __COUNTER__ is being invoked twice in the same line, as is done in the example, then it will return different values.  you could do some integer arithmetic (eg. __COUNTER__/2) to get a number which goes up every other time it's invoked.  also, counter starts at 0, and zero's already in use, so you could try something like (__COUNTER__ + 2)/2.

3. On Feb 14 2009 @ 19:48 guest wrote:

I passed these all 70-649, 70-648, 70-643, 70-642, 70-640 and70-631.

4. On May 19 2009 @ 09:35 guest wrote:

Find louis vuitton handbag and louis  Louis Vuitton Handbags , louis vuitton wallet and louis vuitton purse items on Louis Vuitton Store Browse a huge selection of LV Handbags Louis Vuitton is luxury gifts, French fashion, the replica Louis Vuitton Store is woman best friend. With Louis Vuitton Discover real Louis Vuitton bags, Vuitton accessories and the latest handbag lines. Join the biggest active Louis Vuitton enthusiast community on the web today

UGGs is a brand that is all about luxury and comfort for everyday life. Only the finest quality materials are used to create UGG Boots. Provide UGG Women Boots,UGG Man Boots,UGG Kids Boots.
UGG Australia is the largest distributor of Grade-A sheepskin.
Find Women's UGGs, Men's UGG Boots, and Kids UGGs on Sale all made with ... UGG Store include Discount UGG  UGG Classic Tall,UGG Classic Short

Louis Vuitton is luxury gifts, French fashion, the replica Louis Vuitton Handbag is woman best friend.Monogram Groom.
Offers Discount Louis Vuitton handbags and Louis Vuitton bags and all other designer handbags,free global fast shipping,low price and top quality.Monogram Jokes,Monogram Suede cheap Louis Vuitton
Louis Vuitton.

Looking For Gucci Shoes ? Gucci Store provide gucci Mens shoes,gucci Womens shoes
Wonderful Gucci shoes sale Gucci men's shoes and Gucci women's shoes at discount Gucci Shoes prices.
cheap gucci Shoes
Gucci Shoes and gucci clothing Spring - Summer 2009, Prada Shoes and prada clothing from the Latest Collection 2009 and Dolce Gabbana Clothing 2009
Gucci Loafers
Gucci Sneakers

UGGs
Louis Vuitton Handbags
Gucci Shoes
Louis Vuitton
UGG Boots
Louis Vuitton Handbags
gucci shoes
Monogram Groom
Discount Louis Vuitton
UGG Boots
Louis Vuitton handbags

7. On Jul 14 2009 @ 04:24 guest wrote:

buy wow gold
my wow power leveling
buy wow gold
good wow power leveling
BUY wow gold
my wow power leveling
CHEAP rs gold
cheap wow power leveling
CHEAPEST lotro gold
MY aion gold
buy wow gold
cheap wow gold
CHEAPEST wow gold

9. On Jan 05 2010 @ 14:28 uggbaileybutton wrote:

bailey button uggs

-ugg boots cheap

ugg boots uk

ugg classic

Add a new comment

Name:
Password: (leave empty for anonymous comment)
 
View formatting tags Comment: