Googles appar
Huvudmeny

Post a Comment On: cbloom rants

"03-08-12 - Oodle Coroutines"

5 Comments -

1 – 5 of 5
Blogger jfb said...

Funny thing about coroutines is they are already in common use in games. Badly done, hard to follow, and labeled "Finite State Machines". :)

The switch() hack really does make them usable. I recently implemented USB mass storage firmware -- far easier when the interaction with the PC is procedural, especially to see visibily that it performs as the spec shows.

Here's a trick I came up with recently for the struct coroutine approach, you may find it useful:

Before your switch you have a #define IRQFILTER() or whatnot, and you reserve numbers under some value for your non-IRQ part, and above for your IRQ part. On the event (interrupt in my case), you call the function regardless.

If you make the return() have a version that adds the threshold value to what it would normally return, you now have a way to transport your coroutine up into interrupts and back down. In this case it sets the state variable, pulses and returns. The other handler receives the pulse, state variable is no longer filtering it out from taking action (even if it can be activated some other way), and runs.

On the PC I suppose what you could do with this is move your function between threads, if say one part has to execute in a particular thread, and then move it back out again when it's done.

March 9, 2012 at 12:33 AM

Blogger nereus said...

I love coroutines. In c++11 you can use a (tiny) lambda with a closure to make the macro ick go away. Then the state machine stuff is right there in the reader's face. It's pleasingly elegant. I got the idea from protothreads but I'm not surprised to see you bring them up.

March 9, 2012 at 6:11 AM

Blogger castano said...

> (note the braces which mean that variables in one yield chunk are not visible to the next; this means that the failure of the coroutine to maintain local variables is a compile error and thus not surprising).

This has the effect of not letting being able to yield within a loop. I guess that's what motivates the "YIELD_REPEAT".

Wouldn't be it be more clear to remove the braces from yields and actually express that as a loop?

COROUTINE_START
// open file
YIELD;
// read chunk
YIELD;
do {
// read chunk
// process
YIELD;
} while (!done)
// close file
COROUTINE_END

Visual C++ produces warnings or errors when variables are declared inside a switch, so misuse should be fairly obvious:

error C2360: initialization of 'i' is skipped by 'case' label
warning C4700: uninitialized local variable 'i' used

March 9, 2012 at 12:51 PM

Blogger cbloom said...

Hmm, well, you are right that that works and it looks prettier in some ways/cases.

But in practice you almost always have local variables, and then you get into trouble.

The problem is this bit :

YIELD;
do {
// read chunk
// process
YIELD;
} while (!done)
// close file

which is actually :

return 5; case 5:
// part 1
do {
// part 2
return 6; case 6:
// part 3
} while (!done)

so to do stuff with locals you would have to make it :

YIELD; //return 5; case 5:
{
// part 1
}
do
{
{
// part 2
work->m_done = done;
}
YIELD; // return 6; case 6:
} while ( ! work->m_done )


So I'm not sure if that's actually nicer in practice; maybe I'll try writing some real code like that and see how it goes.

March 10, 2012 at 7:54 PM

Blogger cbloom said...

The really ugly thing about YIELD_REPEAT is it creates a looping scope without that scope being visible at all. eg. there are no braces you can scope-match. It's basically a goto of course.

March 10, 2012 at 9:34 PM

You can use some HTML tags, such as <b>, <i>, <a>

This blog does not allow anonymous comments.

Comment moderation has been enabled. All comments must be approved by the blog author.

You will be asked to sign in after submitting your comment.