RosettaCodeData/Task/Rendezvous/D/rendezvous.d

106 lines
2.9 KiB
D

import std.stdio, std.array, std.datetime, std.exception,
std.concurrency, core.thread, core.atomic;
final class OutOfInk: Exception {
this() pure nothrow {
super("Out of ink.");
}
}
struct Printer {
string id;
size_t ink;
void printIt(in string line) {
enforce(ink != 0, new OutOfInk);
writefln("%s: %s", id, line);
ink--;
}
}
/// Treats shared lvalue as if it is thread-local.
ref assumeThreadLocal(T)(ref shared T what) pure nothrow {
return *cast(T*)&what;
}
struct RendezvousPrinter {
Printer[] printers;
void print(const(string)[] lines) shared {
OutOfInk savedException;
// Lightweight mutual exclusion
// using shared atomic bool.
shared static bool mutex;
void lock() {
while (!cas(&mutex, false, true))
Thread.sleep(1.hnsecs);
}
void unlock() nothrow {
assert(mutex.atomicLoad!(MemoryOrder.acq));
mutex.atomicStore!(MemoryOrder.rel)(false);
}
while (!lines.empty) {
if (printers.empty) {
// No more printers to try.
assert(savedException !is null);
throw savedException;
}
try {
{
lock;
scope(exit) unlock;
printers.front.assumeThreadLocal
.printIt(lines.front);
}
lines.popFront;
// Increase the chance of interleaved output.
Thread.sleep(10.msecs);
} catch (OutOfInk exc) {
savedException = exc;
// Switch to the next printer.
lock;
scope(exit) unlock;
printers.assumeThreadLocal.popFront;
}
}
}
}
void humptyDumptyTask(shared ref RendezvousPrinter rendezvous) {
const humptyDumpty = [
"Humpty Dumpty sat on a wall.",
"Humpty Dumpty had a great fall.",
"All the king's horses and all the king's men,",
"Couldn't put Humpty together again."];
rendezvous.print(humptyDumpty);
}
void motherGooseTask(shared ref RendezvousPrinter rendezvous) {
const motherGoose = ["Old Mother Goose,",
"When she wanted to wander,",
"Would ride through the air,",
"On a very fine gander.",
"Jack's mother came in,",
"And caught the goose soon,",
"And mounting its back,",
"Flew up to the moon."];
rendezvous.print(motherGoose);
}
void main() {
shared rendezvous = RendezvousPrinter
([Printer("main", 5), Printer("reserve", 5)]);
spawn(&humptyDumptyTask, rendezvous);
spawn(&motherGooseTask, rendezvous);
}