+1 rvirding、「並行システムを構築するときに非常に役立ちます」はまさにそれについてです。いくつかのサンプル コード (「喫煙者の問題」の解決策) を思い出しました。しばらく前にクランクアップしました。それを共有すると、ポイントを説明するのに役立つかもしれないと思いました:
-module(smokers).
-export([smokers/0]).
smokers() ->
Rounds = 1000000,
Agent = self(),
lists:foreach(fun(Material) -> spawn(fun() -> startSmoker(Agent, Material) end) end, materials()),
done = agent(Rounds),
io:format("Done ~p rounds~n", [Rounds]).
agent(0) ->
done;
agent(Rounds) ->
offer(twoRandomMaterials(), Rounds).
offer(AvailableMaterials, Rounds) ->
receive
{take, Smoker, AvailableMaterials} ->
Smoker ! smoke,
receive
doneSmoking ->
agent(Rounds - 1)
end
end.
startSmoker(Agent, Material) ->
smoker(Agent, lists:delete(Material, materials())).
smoker(Agent, Missing) ->
Agent ! {take, self(), Missing},
receive
smoke ->
Agent ! doneSmoking,
smoker(Agent, Missing)
end.
twoRandomMaterials() ->
Materials = materials(),
deleteAt(random:uniform(length(Materials)) - 1, Materials).
materials() ->
[paper, tobacco, match].
deleteAt(_, []) -> [];
deleteAt(0, [_ | T]) -> T;
deleteAt(Idx, [H | T]) -> [H | deleteAt(Idx - 1, T)].
ここで興味深いのは、receive {take, Smoker, AvailableMaterials}
. ただし、現在処理できるのはそのうちの1 つだけです。それから握手としてのインナーがあります。したがって、ハンドシェイク メッセージの受信時にコードが何らかの作業を実行できるようにする適切なメッセージの選択と、ハンドシェイク メッセージの受信時に他のメッセージが失われないことが、ここでのすべての同時実行の問題を解決するものです。一致しない/処理不能なメッセージがいずれかの時点でドロップされた場合、は (定期的に要求を繰り返さない限り) 永久に停止します。receive doneSmoking
take
smoker