我试图为众所周知的Dijkstra餐饮哲学家问题实施我自己的解决方案。我给出的只是国家机器,哲学家应该同时抓住两个叉子。
这是我的代码:
-module(assess3).
-compile([export_all]).
-define(EAT,1000).
-define(THINK,1000).
college() ->
R = spawn_link(?MODULE, report,[]),
F1 = spawn_link(?MODULE, fork,["fork1",R]),
F2 = spawn_link(?MODULE, fork,["fork2",R]),
F3 = spawn_link(?MODULE, fork,["fork3",R]),
F4 = spawn_link(?MODULE, fork,["fork4",R]),
F5 = spawn_link(?MODULE, fork,["fork5",R]),
spawn_link(?MODULE, philosopher,["Socrates", R, F1,F2]),
spawn_link(?MODULE, philosopher,["Confucius", R, F2,F3]),
spawn_link(?MODULE, philosopher,["Aristole", R, F3,F4]),
spawn_link(?MODULE, philosopher,["Homer", R, F4,F5]),
spawn_link(?MODULE, sphilosopher,["Plato", R, F1,F5]).
%%create philosophers randomly
philosopher(Name, Report, LeftF, RightF) ->
random:seed(erlang:phash2([node()]),
erlang:monotonic_time(),erlang:unique_integer()),
create_phils(Name,Report,LeftF,RightF).
%%create special philosopher
sphilosopher(Name, Report, RightF, LeftF) ->
random:seed(erlang:phash2([node()]),
erlang:monotonic_time(),erlang:unique_integer()),
create_special_phil(Name,Report,RightF,LeftF).
%%creates random 4 philosophers who get the Left fork first then the right fork
create_phils(Name,Report,LeftF,RightF) ->
%%thinking state
reporting(Name,Report,thinking),
timer:sleep(random:uniform(?THINK)),
%%hungry state
reporting(Name,Report,hungry),
LeftF ! RightF! {pick,self()},
receive
{pick, LeftF} -> reporting(Report, Name, left);
{pick, RightF} -> reporting(Report, Name, right)
end,
receive
{pick, LeftF} -> reporting(Report, Name, left);
{pick, RightF} -> reporting(Report, Name, right)
end,
%%eating state
reporting(Report,Name,eating),
timer:sleep(random:uniform(?EAT)),
LeftF ! RightF ! {let_go,self()},
create_phils(Name,Report,LeftF,RightF).
%%create special philosopher who attempts to communicate first with the
%%right fork proccess instead of the left fork
create_special_phil(Name,Report,RightF,LeftF) ->
%%thinking state
reporting(Name,Report,thinking),
timer:sleep(random:uniform(?THINK)),
%%hungry state
reporting(Name,Report,hungry),
RightF ! LeftF ! {pick,self()},
receive
{pick, RightF} -> reporting(Report, Name, right);
{pick, LeftF} -> reporting(Report, Name, left)
end,
receive
{pick, RightF} -> reporting(Report, Name, right);
{pick, LeftF} -> reporting(Report, Name, left)
end,
%%eating state
reporting(Report,Name,eating),
timer:sleep(random:uniform(?EAT)),
RightF ! LeftF ! {let_go,self()},
create_special_phil(Name,Report,RightF,LeftF).
%%prepares what the Report proccess will print
reporting(Name,Report,Status) ->
Report ! {Name,Status,self()},
receive
{Report,ack} -> true
end.
%%Report proccess, receives and prints
report() ->
receive
{Name,Status, Pid} ->
io:format("~s : ~s ~n",[Name,status(Status)]),
Pid ! {ack,self()},
report()
end.
%%function to pass the appropriate status in string for io:format
status(Status) ->
case Status of
thinking -> "is thinking";
hungry -> "is hungry";
eating -> "is eating";
right -> "got right fork";
left -> "got left fork";
on_table -> "on table";
in_use ->"in use";
Status -> atom_to_list(Status)
end.
fork(Name,Report) ->
receive
{picked,Pid} ->
reporting(Report,Name,in_use),
Pid ! {picked,self()},
receive
{let_go,Pid} ->
reporting(Report,Name,on_table)
end,
fork(Name,Report)
end.
我没有得到任何错误,但是当我尝试在Erlang shell中运行assess3:college().
时,而不是看到进程通信,我所看到的只是:
苏格拉底:正在思考 孔子:正在思考 < 0.265.0>
Aristole:正在思考 荷马:正在思考 柏拉图:正在思考
我不明白为什么会这样,因为在我开始编码之前,我手工设计了所有内容以避免迷路。任何帮助表示赞赏。
PS。这个实现应该可以防止死锁,因为四个哲学家首先抓住左叉,而第五个人首先尝试选择正确的叉子,尽管我确实知道这可能会导致资源饥饿,这意味着一个哲学家可能永远不会吃东西。我现在不关心这一点 - 一步一步。
答案 0 :(得分:1)
您有几个与错误消息不匹配的问题,以及错误顺序的函数参数。不匹配的消息导致事物挂起,永远等待从未发送的消息。修复这些问题会导致崩溃,因为参数不正确。
例如,请考虑您的fork
功能:
fork(Name,Report) ->
receive
{picked,Pid} ->
reporting(Report,Name,in_use),
Pid ! {picked,self()},
receive
{let_go,Pid} ->
reporting(Report,Name,on_table)
end,
fork(Name,Report)
end.
它正在等待{picked,...}
消息,但是您的哲学家正在发送{pick,...}
条消息,并且它正在回复{picked,...}
消息,但哲学家们希望收到{pick,...}
条消息
查看您的report
功能:
report() ->
receive
{Name,Status, Pid} ->
io:format("~s : ~s ~n",[Name,status(Status)]),
Pid ! {ack,self()},
report()
end.
它会将{ack, self()}
消息发送回Pid
,但这些进程需要{Report, ack}
条消息。
在许多地方,您拨打reporting(Report,Name,...)
Report
和Name
参数的顺序错误。
这是一个似乎有用的固定版本。
-module(assess3).
-compile([export_all]).
-define(EAT,1000).
-define(THINK,1000).
college() ->
R = spawn_link(?MODULE, report,[]),
F1 = spawn_link(?MODULE, fork,["fork1",R]),
F2 = spawn_link(?MODULE, fork,["fork2",R]),
F3 = spawn_link(?MODULE, fork,["fork3",R]),
F4 = spawn_link(?MODULE, fork,["fork4",R]),
F5 = spawn_link(?MODULE, fork,["fork5",R]),
spawn_link(?MODULE, philosopher,["Socrates", R, F1,F2]),
spawn_link(?MODULE, philosopher,["Confucius", R, F2,F3]),
spawn_link(?MODULE, philosopher,["Aristole", R, F3,F4]),
spawn_link(?MODULE, philosopher,["Homer", R, F4,F5]),
spawn_link(?MODULE, sphilosopher,["Plato", R, F1,F5]).
%%create philosophers randomly
philosopher(Name, Report, LeftF, RightF) ->
random:seed(erlang:phash2([node()]),
erlang:monotonic_time(),erlang:unique_integer()),
create_phils(Name,Report,LeftF,RightF).
%%create special philosopher
sphilosopher(Name, Report, RightF, LeftF) ->
random:seed(erlang:phash2([node()]),
erlang:monotonic_time(),erlang:unique_integer()),
create_special_phil(Name,Report,RightF,LeftF).
%%creates random 4 philosophers who get the Left fork first then the right fork
create_phils(Name,Report,LeftF,RightF) ->
%%thinking state
reporting(Name,Report,thinking),
timer:sleep(random:uniform(?THINK)),
%%hungry state
reporting(Name,Report,hungry),
LeftF ! RightF ! {pick,self()},
receive
{picked, LeftF} -> reporting(Name, Report, left);
{picked, RightF} -> reporting(Name, Report, right)
end,
receive
{picked, LeftF} -> reporting(Name, Report, left);
{picked, RightF} -> reporting(Name, Report, right)
end,
%%eating state
reporting(Name,Report,eating),
timer:sleep(random:uniform(?EAT)),
LeftF ! RightF ! {let_go,self()},
create_phils(Name,Report,LeftF,RightF).
%%create special philosopher who attempts to communicate first with the
%%right fork proccess instead of the left fork
create_special_phil(Name,Report,RightF,LeftF) ->
%%thinking state
reporting(Name,Report,thinking),
timer:sleep(random:uniform(?THINK)),
%%hungry state
reporting(Name,Report,hungry),
RightF ! LeftF ! {pick,self()},
receive
{picked, RightF} -> reporting(Name, Report, right);
{picked, LeftF} -> reporting(Name, Report, left)
end,
receive
{picked, RightF} -> reporting(Name, Report, right);
{picked, LeftF} -> reporting(Name, Report, left)
end,
%%eating state
reporting(Name,Report,eating),
timer:sleep(random:uniform(?EAT)),
RightF ! LeftF ! {let_go,self()},
create_special_phil(Name,Report,RightF,LeftF).
%%prepares what the Report proccess will print
reporting(Name,Report,Status) ->
Report ! {Name,Status,self()},
receive
{Report,ack} -> ok
end.
%%Report proccess, receives and prints
report() ->
receive
{Name,Status,Pid} ->
io:format("~s : ~s ~n",[Name,status(Status)]),
Pid ! {self(),ack},
report()
end.
%%function to pass the appropriate status in string for io:format
status(Status) ->
case Status of
thinking -> "is thinking";
hungry -> "is hungry";
eating -> "is eating";
right -> "got right fork";
left -> "got left fork";
on_table -> "on table";
in_use ->"in use";
Status -> atom_to_list(Status)
end.
fork(Name,Report) ->
receive
{pick,Pid} ->
reporting(Name,Report,in_use),
Pid ! {picked,self()},
receive
{let_go,Pid} ->
reporting(Name,Report,on_table)
end,
fork(Name,Report)
end.