前に参加したHaskellによる並列・並行プログラミングの読書会にて、
#heyhey_haskell 7.5の無制限チャネルはC言語みたいなポイント操作が素敵でした
— にへまk (@nihemak) January 24, 2015
×ポイント操作
◯ポインタ操作
— にへまk (@nihemak) 2015, 1月 24
で、やってみようと思いました。C言語はリソース管理とか色々めんどくなったのでD言語にしました。バージョンはv2.066.1です。mallocさん、さようなら。
まずは、MVar作りました。例外とかはガン無視です。
MVarはProducer-ConsumerパターンのChannelの事です。
以下コードです。増補改訂版Java言語で学ぶデザインパターン入門マルチスレッド編の5章の”Producer-Consumer - わたしが作り、あなたが使う”を見ながら実装しました。
// MVar.d module MVar; import core.sync.mutex; import core.sync.condition; class MVar(T) { private Mutex m; private Condition c; private T[] value; this() { value = null; m = new Mutex; c = new Condition(m); } void put(T v) { synchronized(m) { while (value != null) { c.wait(); } value = [v]; c.notifyAll(); } } T take() { synchronized(m) { while (value == null) { c.wait(); } auto v = value[0]; value = null; c.notifyAll(); return v; } } }
とりあえず、Haskellによる並列・並行プログラミングの7.3の”簡単なチャネルとしてのMVar:ログサービス”をやってみました。
// Logger.d import std.stdio; import std.variant; import core.thread; import MVar; class Logger { struct Message { string message; } struct Stop { MVar.MVar!(bool) m; } alias Command = Algebraic!(Message, Stop); private MVar.MVar!(Command) m; this() { m = new MVar.MVar!(Command); auto t = new Thread( { while (true) { auto cmd = m.take(); if (cmd.type == typeid(Message)) { auto msg = cmd.get!Message.message; writeln(msg); } else if (cmd.type == typeid(Stop)) { auto s = cmd.get!Stop.m; writeln("logger: stop"); s.put(true); break; } } }); t.start(); } void message(string msg) { Message message = { message:msg }; Command cmd = message; m.put(cmd); } void stop() { auto s = new MVar.MVar!(bool); Stop stop = { m:s }; Command cmd = stop; m.put(cmd); s.take(); } } void main() { auto l = new Logger; l.message("hello"); l.message("bye"); l.stop(); }
動いたー
$ dmd Logger.d MVar.d $ ./Logger hello bye logger: stop