【问题标题】:Dining Philosophers (my implementation) processes don't communicateDining Philosophers(我的实现)流程不沟通
【发布时间】:2016-06-19 09:32:37
【问题描述】:

我正在尝试为著名的 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(). 时,我看到的只是进程通信,而不是:

苏格拉底:在思考
孔子:在想

亚里士多德:在思考
荷马:在思考
柏拉图:在思考

我不明白为什么会发生这种情况,因为在我开始编码之前,我都是手工设计的,以避免迷路。任何帮助表示赞赏。

PS。这个实现应该防止死锁,因为四个哲学家先抓住左叉,第五个尝试先选择右叉,尽管我知道这可能会导致资源匮乏,这意味着一个哲学家可能永远不会吃东西。我暂时不关心这个——一次一步。

【问题讨论】:

    标签: concurrency erlang


    【解决方案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,...),其中 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.
    

    【讨论】:

      猜你喜欢
      • 2017-11-28
      • 1970-01-01
      • 2018-09-05
      • 1970-01-01
      • 2017-03-02
      • 2011-06-04
      • 1970-01-01
      • 1970-01-01
      • 2018-12-27
      相关资源
      最近更新 更多