Coroutines in D

Andrej Mitrovic none at none.none
Tue May 3 11:06:38 PDT 2011


I'm trying to figure out how to use coroutines in D.

First, I think I've run into some kind of bug. I've followed this C++ example: http://www.subatomicglue.com/secret/coro/readme.html, and came up with this:

import std.stdio;
import core.thread;

void fiberFunc(size_t arg)
{
    int i = 0;

    foreach (x; 0 .. 1000)
    {
        writefln("fiber waiting (id = %d)", arg);
        Fiber.yield();
    }

    foreach (x; 0 .. 1000)
    {
        writefln("fiber running (iter = %d id = %d)", ++i, arg);
        Fiber.yield();
    }

    while (1)
    {
        writefln("fiber waiting (id = %d)", arg);
        Fiber.yield();
    }
}

void main()
{
    Fiber[200] fibers;

    foreach (ref fiber; fibers)
    {
        fiber = new Fiber(&fiberFunc);
    }

    while (true)
    {
        foreach (fiber; fibers)
        {
            fiber.call();
        }
    }
}

Only after I've translated the C++ example to D I've realized that fiberFunc actually takes an argument. But from what I can tell core.thread.Fiber never calls this function with any arguments. I have a hunch that "arg" ends up having an uninitialized garbage value, so it looks like this is a bug?

Ok, that put aside what I really want to emulate is this Python example of a coroutine (perhaps bearophile is familiar with this):

def coroutine(func):
    def start(*args,**kwargs):
        cr = func(*args,**kwargs)
        cr.next()
        return cr
    return start

@coroutine
def unwrap_protocol(header='\x61',
                    footer='\x62',
                    dle='\xAB',
                    after_dle_func=lambda x: x,
                    target=None):
    """ Simplified framing (protocol unwrapping)
        co-routine.
    """
    # Outer loop looking for a frame header
    #
    while True:
        byte = (yield)
        frame = ''

        if byte == header:
            # Capture the full frame
            #
            while True:
                byte = (yield)
                if byte == footer:
                    target.send(frame)
                    break
                elif byte == dle:
                    byte = (yield)
                    frame += after_dle_func(byte)
                else:
                    frame += byte

@coroutine
def frame_receiver():
    """ A simple co-routine "sink" for receiving
        full frames.
    """
    while True:
        frame = (yield)
        print 'Got frame:', frame.encode('hex')


bytes = ''.join(chr(b) for b in
            [0x70, 0x24,
             0x61, 0x99, 0xAF, 0xD1, 0x62,
             0x56, 0x62,
             0x61, 0xAB, 0xAB, 0x14, 0x62,
             0x7
            ])

unwrapper = unwrap_protocol(target=frame_receiver())

for byte in bytes:
    unwrapper.send(byte)

This was taken from Eli's blog: http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-to-state-machines/

I'm not seeing any way of yielding a value back from a Fiber or even sending it, so I don't see how I can use fibers to implement coroutines which send or return values. But I'm new to the concept so maybe I'm missing something obvious?





More information about the Digitalmars-d-learn mailing list