ErlangでProducer-Consumerパターン
30分プログラム、その371。増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編に載っているProducer-ConsumerパターンをErlangでやってみる。
Javaと違ってwait()が無いので、キューが空のときにgetを待たせるのが結構、大変だった。やっぱり、JavaのデザインパターンをそのままErlangで使うのは無理があるかもしれない。
あと元のやつと違って、キューの長さを制限してない。キューが空のときの処理を書いてたら、時間がなくなった。
使い方
1> producer_consumer:main(). Cake A(0) --> Cake B(0) --> <-- eat Cake A(0) Cake B(1) --> Cake A(1) --> <-- eat Cake B(0) <-- eat Cake B(1) Cake A(2) --> Cake B(2) --> <-- eat Cake A(1)
ソースコード
-module(producer_consumer). -compile([export_all]). % ケーキを置くテーブル table() -> table(queue:new(),[]). table(Q1,Waiting) -> receive {get,From} -> case queue:out(Q1) of {{value,Item},Q2} -> From ! {ok,Item}, table(Q2,Waiting); {empty, _ } -> table(Q1,[From|Waiting]) end; {put,From,Item} -> case Waiting of [H|T] -> H ! {ok,Item}, From ! {ok}, table(Q1,T); [] -> Q2 = queue:in(Item,Q1), From ! {ok}, table(Q2,Waiting) end end. % ケーキを作ってテーブルに置くスレッド maker(Table,Name) -> maker(Table,Name,0). maker(Table,Name,Id) -> Cake = io_lib:format("~s(~p)",[Name,Id]), Table ! {put,self(),Cake}, io:format("~s -->~n",[Cake]), receive {ok} -> timer:sleep(2000), maker(Table,Name,Id+1) end. % テーブルに置かれたケーキを食べるスレッド eater(Table) -> timer:sleep(1000), Table ! {get,self()}, receive {ok,Item} -> io:format("\t<-- eat ~s~n",[Item]), eater(Table) end. main() -> Table = spawn(fun () -> table() end), spawn(fun () -> maker(Table,"Cake A") end), spawn(fun () -> maker(Table,"Cake B") end), eater(Table).