【问题标题】:Dining Philosophers in Erlang二郎餐厅哲学家
【发布时间】:2015-05-05 02:42:26
【问题描述】:

如果您以前看过《哲学家进餐》,那么您知道有几种方法可以做到这一点。我的实现创建了与消息传递通信的哲学家和分叉进程。

我在 fork 和哲学家进程上有很多格式的程序,但我自己想通了,现在我将分享完成的代码。我是初学者,仅供参考。祝你有美好的一天。

-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.

【问题讨论】:

  • 你在这里乞求一个问题,“为什么要在 Erlang 中实现哲学家就餐问题?” DPP 说明了在进行基于锁的并发控制时遇到的问题。 Erlang 是专门为避免显式锁定的需要而设计的,但是您已经离开并重新引入了它。 为什么?

标签: erlang


【解决方案1】:

马上,我注意到两件事:

  1. 您有多个未终止的receive 块——即没有end 可匹配。请参阅 Erlang/OTP 文档here
  2. 您可能有非法守卫。而不是 string:equal,您可能想看看简单的术语比较是否适合您。请参阅 Erlang/OTP 文档here

最后,我知道复制和粘贴到 Stackoverflow 问题很容易,而且不用担心格式化,但如果你的编辑器屏幕看起来像上面的代码,你可能想为你的首选安装 Erlang 语言支持编辑。缩进可以成为你的朋友。 :-)

【讨论】:

    猜你喜欢
    • 2013-05-10
    • 1970-01-01
    • 2016-03-04
    • 2015-10-14
    • 1970-01-01
    • 2018-01-21
    • 2013-01-28
    • 1970-01-01
    • 2022-12-29
    相关资源
    最近更新 更多