So I'm porting so #golang code to #dlang and there is all these blasted
"go" statements.So I thought I'd give implmenting it in D a shot. What do
you guys think?
Fire away :).

import std.stdio;
import core.thread : Thread;
import core.sync.mutex : Mutex;
import core.time;

void main() {
    auto ch = chan!int(1);
    go!({
        foreach (i; 22..44) {
            ch._ = i;
        } });

    foreach (i; 0..10) {
        writeln("pop: ", ch._);
    }
}

// Implementation

void go(alias F)() {
    auto t = new Thread(F);
    t.isDaemon(true); // we don't care if this thread dies.
    t.start();
}

/**
 * chan allows messaging between threads without having to deal with locks,
similar to how chan works in golang
 */
class chan_(T) {
    shared Mutex lock;
    struct Container(T) {
        T value;
        Container!T* next;
    }
    shared Container!T* buf;
    shared Container!T* last;
    shared size_t length;
    shared void insert(shared T v) {
        shared Container!T* newItem = new shared Container!T();
        newItem.value = v;
        if (buf is null) {
            buf = newItem;
            last = newItem;
        } else {
            last.next = newItem;
            last = newItem;
        }
        length++;
    }
    shared T popFront() {
        T ret;
        synchronized (lock) {
            ret = buf.value;
            buf = buf.next;
            length--;
        }
        return ret;
    }
    size_t maxItems;
    bool blockOnFull = false;
    this(int maxItems = 1024, bool blockOnFull = true) {
        lock = cast(shared)new Mutex;
        length = 0;

        this.maxItems = maxItems;
        this.blockOnFull = blockOnFull;
    }

    @property
    shared void _(T value) {
        bool done;
        while(true) {
            synchronized(lock) {
                if (!done && length < maxItems) {
                    insert(value);
                    done = true;
                } else if (!blockOnFull) {
                    throw new ChannelFull("Channel Full");
                }
                if (length <= maxItems-1) {
                    break;
                }
            }
            Thread.sleep(dur!"msecs"(5));
        }
    }
    @property
    shared T _() {
        while(true) {
            size_t len;
            synchronized(lock) {
                len = length;
            }
            if (len > 0) {
                break;
            }
            Thread.sleep(dur!"msecs"(5));
        };
        auto r = popFront();
        return r;
    }
}
auto chan(T)(int n, bool blockOnFull = true) {
    return cast(shared)new chan_!T(n, blockOnFull);
}

class ChannelFull : Exception {
    this(string msg, string file = __FILE__, ulong line =
cast(ulong)__LINE__, Throwable next = null) {
        super(msg,file,line,next);
    }
}

Reply via email to