2016-03-05 36 views
0

我试图实现我自己的解决方案,为众所周知的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>
亚里士多德:正在考虑
荷马:正在考虑
柏拉图:正在考虑

我不明白,为什么出现这种情况,因为之前我就开始编码,我设计的手,以避免迷路的一切。任何帮助赞赏。

PS。这个实现是为了防止死锁,因为四个哲学家首先抓住左边的叉子,第五个先尝试先选择正确的叉子,但我明白,这可能会陷入资源匮乏,意味着一个哲学家可能永远不会吃东西。我现在不在乎这个,现在只需一步一步完成。

回答

2

您有几个与错误消息和函数参数错误顺序有关的问题。不匹配的消息导致事情永远等待永远不会发送的消息。解决这些问题会导致崩溃,因为不正确的参数问题。

例如,请考虑您的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,...),其中参数ReportName的顺序错误。

这是一个固定的版本,似乎工作。

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