
Coroutines in C - Rexxar
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
======
adw
The guy behind this article (Simon) is the lead author of PuTTY and was the
lead author of nasm. Seriously smart dude.

~~~
camccann
Alas, he's also responsible for one of my worst time-wasting habits:
<http://www.chiark.greenend.org.uk/~sgtatham/puzzles/>

~~~
mbrubeck
That's the same guy? Damn, any productivity I've gotten thanks to PuTTY has
totally been cancelled out by those puzzles.

------
richcollins
Io's coroutine library is separate from the VM and open source:

<http://dekorte.com/projects/opensource/libcoroutine/>

~~~
draegtun
ditto for Perl: <http://search.cpan.org/dist/Coro/>

~~~
richcollins
You can use that library outside of Perl?

------
mrshoe
Stackless Python is cool, but don't you wish there was a library that made
coroutines clean and easy in vanilla Python?

EDIT: whoops, I meant to say continuations, as camccann was kind enough to
point out.

~~~
camccann
Vanilla Python _has_ coroutines, as of version 2.5. See here:
<http://www.python.org/doc/2.5/whatsnew/pep-342.html>

Basically it works by letting you send a value into a generator function,
which then appears as the return value of the most recent yield statement. I
have abused this feature horribly at times to create cooperatively
multitasking lightweight pseudo-threads. Good times, that.

What vanilla does _not_ and likely never will have, that Stackless does allow,
are full continuations, a.k.a. the Dark Lord of All Flow Control Structures.

~~~
duskwuff
Sadly, using generators as coroutines falls apart badly as soon as you try to
perform a subroutine call. There's no easy way (at least, not that I've come
up with) to call a coroutine sub from a coroutine without copious glue.

~~~
camccann
Wandering progressively off-topic...

I wouldn't call it "copious", necessarily. It's easily reusable, at least. My
aforementioned cooperative multitasking hackery involved inheriting from a
base "coroutine-able" class that, among other things, kept a per-instance
execution stack that would be updated by the dispatching loop depending on the
value yielded by the generator. The end result would look something like this:

    
    
      def foo(self):
          spam = 1
          while True:
              yield self.call(self.spam_and_eggs, spam)
              spam += 1
    
      def spam_and_eggs(self, spam):
          print ("spam, " * spam) + "and eggs"
          if spam >= 20:
              yield self.halt()
          else:
              yield self.wait(2)
          yield self.ret()
    

Which would print another item off the menu every other cycle of the
dispatcher loop, until 20 "spams" at which point the "thread" would stop.

Other actions included a goto (clear the stack and jump to a new generator
method), conditional waits (keep running the thread unless, say, 2 miliseconds
have elapsed since it started this cycle), and "message passing" between
threads (push something onto another instance's stack). The main _downside_
was that stack traces from exceptions inside a faux-thread were singularly
useless, though I was working on some debugging tools for code using it.

The guts of it amounted to maybe a few hundred lines of code, most of which is
the dispatch loop and bookkeeping for message queues. One of these days I
ought to clean it up and post the code on the web somewhere, but unfortunately
I'm currently in a somewhat sticky spot and looking for work (and I fear that
spending more time on things like building cooperative multitasking in Python
than things to further my humdrum day-job career has not been a great help
thus far).

------
jrockway
libcoro: <http://software.schmorp.de/pkg/libcoro.html>

~~~
draegtun
libtask: <http://news.ycombinator.com/item?id=676522>

------
loup-vaillant
Or you could use lazy evaluation (on the producer). In this case, a simple
stream is enough. Then, you call both the producer and the consumer (`return
consume(produce());`)

Horrible in C, but beautiful in languages with GC and lambdas.

------
shin_lao
I can't help but think about how you can build a state machine in C++
templates that achieve the same result with type safety, no overhead and no
risk of running into compilers generated problems.

------
skwiddor
<http://swtch.com/~rsc/thread/>

<http://swtch.com/libtask/>

