Dining Philosophers in Erlang

2019-03-05 05:58发布

问题:

If you have ever seen Dining Philosophers before, then you know that there are a few ways to do it. My implementation creates philosopher and fork processes which communicate with message passing.

I was having a lot of program with format on the fork and philosopher processes, but I figured it out myself and now I will share the finished code. I'm a beginner fyi. Have a nice day.

-module(df).
-export([start/0, fork/2, philosopher/5]).

start() ->
SpawnForks = spawnForks([1,2,3,4], []),
SpawnForks2 = lists:reverse(SpawnForks),
main(SpawnForks2, [], 1).


%Creates a list of spawned fork processes
spawnForks([], ForkList) -> ForkList;
spawnForks([Head|Tail], ForkList) ->
  Fork = spawn(df,fork,[Head, "down"]),
spawnForks(Tail, [Fork|ForkList]).


%Philosopher 4 will have a different fork order
main(ForkList, PhilList, Count) when Count =:= 4 ->
  Fork1 = lists:nth(Count, ForkList),
  Fork2 = lists:nth(1, ForkList),
  %arguments to the philosopher: (Count = PhilosopherNumber, 2 = number of times to eat, fork1, fork2, self
  Philosopher = spawn(df, philosopher, [Count, 2, Fork1, Fork2, self()]),
  await([Philosopher|PhilList], ForkList);

  %philosophers 1-3 will have standard fork order.
main(ForkList, PhilList, Count) ->  
  Fork1 = lists:nth(Count, ForkList),
  Fork2 = lists:nth(Count + 1, ForkList),
  %arguments to the philosopher: (Count = PhilosopherNumber, 2 = number of times to eat, fork1, fork2, self
  Philosopher = spawn(df, philosopher, [Count, 2, Fork2, Fork1, self()]),
  Count2 = Count + 1,
main(ForkList, [Philosopher|PhilList], Count2).


%await waits for philosophers to be done and shuts down the fork processes
await([],[])-> ok;
await([],[Head|Tail]) -> 
    Head ! {shutdown}, await([], Tail);
await([Pid|Rest], ForkList)->
    receive {done, Pid} ->
    await(Rest, ForkList)
end.



%a fork process
%when state == down, accept pickup messages. After receiving a pickup request, 
%send an authorization. Print "fork up", and set fork State to up.
fork(Fork,State) when State =:= "down" ->
receive 
    {shutdown} -> exit(normal);
    {pickup, Pid, Philosopher} -> 
    io:format("Philosopher ~p picks up Fork ~p.\n",[Philosopher,Fork]),
    Pid ! {getfork, self()},
fork(Fork,"up")
    end;
%when state == up, accept putdown messages. After receiving a putdown request, 
%send an authorization. Print "fork up" and set fork State to up.
fork(Fork,State) when State =:= "up" ->
    receive
    {shutdown} -> exit(normal);
    {putdown, Pid, Philosopher} ->
    Pid ! {takefork, self()},
    io:format("Philosopher ~p puts down Fork ~p.\n",[Philosopher,Fork]),
fork(Fork,"down")
end.



%a philosopher process 
philosopher(_, Times, _,_, Main) when Times =:= 0 -> Main ! {done, self()}, exit(normal);
philosopher(Philosopher, Times, Fork1, Fork2, Main)->  
    io:format("Philosopher ~p is thinking.\n",[Philosopher]),
%request fork pickups on adjacent forks. wait for authorization messages and print "eating" 
    Fork1 ! {pickup, self(), Philosopher},
    receive 
    {getfork, Fork1} ->
                Fork2 ! {pickup, self(), Philosopher}
    end,
    receive         
    {getfork, Fork2} -> 
                io:format("Philosopher ~p is eating.\n",[Philosopher]),
                Fork1 ! {putdown, self(), Philosopher},
                Fork2 ! {putdown, self(), Philosopher},
                receive
                {takefork, Fork1} -> ok;
                {takefork, Fork2} -> ok
    end,
                Times2 = Times - 1,
philosopher(Philosopher, Times2, Fork1, Fork2, Main)
    end.

回答1:

Right off the bat, I noticed two things:

  1. You have multiple unterminated receive blocks -- i.e., no end to match. See Erlang/OTP docs here.
  2. You likely have illegal guards. Instead of string:equal, you probably want to see if simple term comparison will work for you. See Erlang/OTP docs here.

Finally, I know it's easy to copy & paste into a Stackoverflow question and not bother with formatting, but on the chance that your editor screen looks anything like that code above, you probably want to install the Erlang language support for your preferred editor. Indentation can be your friend. :-)



标签: erlang