Dining philosophers: Difference between revisions
Content added Content deleted
No edit summary |
|||
Line 2,071: | Line 2,071: | ||
end -- class FORK</lang> |
end -- class FORK</lang> |
||
=={{header|Elixir}}== |
|||
Implements the Chandy-Misra algorithm. |
|||
<lang Elixir> |
|||
defmodule DiningPhilosophers do |
|||
defstruct missing: [], clean: [], promised: [] |
|||
def run_demo do |
|||
pid1 = spawn(__MODULE__, :init, ["Russell"]) |
|||
pid2 = spawn(__MODULE__, :init, ["Marx"]) |
|||
pid3 = spawn(__MODULE__, :init, ["Spinoza"]) |
|||
pid4 = spawn(__MODULE__, :init, ["Kant"]) |
|||
pid5 = spawn(__MODULE__, :init, ["Aristotle"]) |
|||
send(pid1, {:run, %Philosopher{}}) |
|||
send(pid2, {:run, %Philosopher{missing: [pid1]}}) |
|||
send(pid3, {:run, %Philosopher{missing: [pid2]}}) |
|||
send(pid4, {:run, %Philosopher{missing: [pid3]}}) |
|||
send(pid5, {:run, %Philosopher{missing: [pid1, pid4]}}) |
|||
end |
|||
def init(name) do |
|||
receive do |
|||
{:run, state} -> |
|||
spawn(__MODULE__, :change_state, [self()]) |
|||
case Enum.random(0..1) do |
|||
0 -> thinking(name, state) |
|||
1 -> hungry(name, state) |
|||
end |
|||
end |
|||
end |
|||
defp thinking(name, state) do |
|||
receive do |
|||
{:change_state} -> |
|||
hungry(name, state) |
|||
{:chopstick_request, pid} -> |
|||
%{missing: missing} = state |
|||
if clean?(pid, state) do |
|||
thinking(name, promise_chopstick(name, pid, state)) |
|||
else |
|||
give_chopstick(name, self(), pid) |
|||
thinking(name, %{state | missing: [pid | missing]}) |
|||
end |
|||
end |
|||
end |
|||
defp hungry(name, state) do |
|||
IO.puts "#{name} is hungry." |
|||
%{missing: missing} = state |
|||
for pid <- missing, do: request_chopstick(name, self(), pid) |
|||
wait_for_chopsticks(name, state) |
|||
end |
|||
defp wait_for_chopsticks(name, state) do |
|||
%{missing: missing} = state |
|||
if Enum.empty?(missing) do |
|||
eating(name, state) |
|||
end |
|||
receive do |
|||
{:chopstick_request, pid} -> |
|||
%{missing: missing} = state |
|||
if clean?(pid, state) do |
|||
wait_for_chopsticks(name, promise_chopstick(name, pid, state)) |
|||
else |
|||
give_chopstick(name, self(), pid) |
|||
request_chopstick(name, self(), pid) |
|||
wait_for_chopsticks(name, %{state | missing: [pid | missing]}) |
|||
end |
|||
{:chopstick_response, pid} -> |
|||
%{missing: missing, clean: clean} = state |
|||
wait_for_chopsticks(name, %{state | missing: List.delete(missing, pid), clean: [pid | clean]}) |
|||
end |
|||
end |
|||
defp eating(name, state) do |
|||
IO.puts "*** #{name} is eating." |
|||
receive do |
|||
{:change_state} -> |
|||
%{promised: promised} = state |
|||
for pid <- promised, do: give_chopstick(name, self(), pid) |
|||
thinking(name, %Philosopher{missing: promised}) |
|||
end |
|||
end |
|||
defp clean?(pid, state) do |
|||
%{clean: clean} = state |
|||
Enum.member?(clean, pid) |
|||
end |
|||
defp promise_chopstick(name, pid, state) do |
|||
IO.puts "#{name} promises a chopstick." |
|||
%{promised: promised} = state |
|||
%{state | promised: [pid | promised]} |
|||
end |
|||
defp request_chopstick(name, snd_pid, recv_pid) do |
|||
IO.puts "#{name} requests a chopstick." |
|||
send(recv_pid, {:chopstick_request, snd_pid}) |
|||
end |
|||
defp give_chopstick(name, snd_pid, recv_pid) do |
|||
IO.puts "#{name} gives a chopstick." |
|||
send(recv_pid, {:chopstick_response, snd_pid}) |
|||
end |
|||
def change_state(pid) do |
|||
Process.sleep(Enum.random(1..10) * 1000) |
|||
send(pid, {:change_state}) |
|||
change_state(pid) |
|||
end |
|||
end |
|||
</lang> |
|||
=={{header|Erlang}}== |
=={{header|Erlang}}== |