Erlang - 用餐哲学家的错误

时间:2011-11-10 01:11:01

标签: concurrency erlang

如果代码难以理解,我道歉。 这是经典的餐饮哲学家问题,有5位哲学家正在吃饭,但只有5支 - 你需要两只才能吃。

如果有人有兴趣,这些是说明: http://www.kth.se/polopoly_fs/1.260940!/Menu/general/column-content/attachment/philosophers.pdf

无论如何,这里是代码,筷子过程代码:

-module(chopstick).
-export([start/0]).

start() ->
spawn_link(fun() -> init() end).
init() ->
available().

available() ->
receive
    {request, From} -> 
        From ! granted,
        gone();
    quit ->
        ok
        end.
gone() ->
receive
    returned ->
        available();
    quit ->
        ok
        end.

哲学家流程代码:

-module(eater).
-import(timer, [sleep/1]).
-import(random, [uniform/1]).
-export([start/5, dream/5, eat/5, wait/5]).

start(Hungry, Right, Left, Name, Ctrl) ->
dream(Hungry, Right, Left, Name, Ctrl).

 **%This was wrong, it should say start(Hungry, Right, Left, Name, Ctrl) ->
 spawn_link(fun() -> dream(Hungry, Right, Left, Name, Ctrl) end).**

dream(Hungry, Right, Left, Name, Ctrl) -> 
Time = 500+uniform:random(500),   **%This was wrong, it should say random:uniform**
timer:sleep(Time),
Right! {request, self()},
Left! {request, self()},
%skicka {request, self()} till två pinnar
wait(Hungry, Right, Left, Name, Ctrl).

wait(Hungry, Right, Left, Name, Ctrl) ->
receive
    granted ->  
        io:format("~s received a chopstick~n", [Name]),
        receive
            granted ->
            io:format("~s received a chopstick~n", [Name]),
            io:format("~s started eating~n", [Name]),
            eat(Hungry, Right, Left, Name, Ctrl)
            end;
    _ -> wait(Hungry, Right, Left, Name, Ctrl)
end.

eat(Hungry, Right, Left, Name, Ctrl) ->
Time = 500+uniform:random(500), **%This was wrong, it should say random:uniform**
timer:sleep(Time),
Right! returned,
Left! returned,
io:format("~s put back two chopsticks~n", [Name]),
if 
    Hungry =< 1 ->
        Ctrl ! done;
    true ->
        dream(Hungry-1, Right, Left, Name, Ctrl)
end.    

最后主持人进程:

-module(dinner).
-export([start/0]).


start() ->
spawn(fun() -> init() end).

init() ->
C1 = chopstick:start(),
C2 = chopstick:start(),
C3 = chopstick:start(),
C4 = chopstick:start(),
C5 = chopstick:start(),
Ctrl = self(),
eater:start(5, C1, C2, "Confucios", Ctrl),  **% This is where it crashes**
eater:start(5, C2, C3, "Avicenna", Ctrl),
eater:start(5, C3, C4, "Plato", Ctrl),
eater:start(5, C4, C5, "Kant", Ctrl),
eater:start(5, C5, C1, "Descartes", Ctrl),
wait(5, [C1, C2, C3, C4, C5]).


wait(0, Chopsticks) ->
lists:foreach(fun(C) -> C ! quit end, Chopsticks);
wait(N, Chopsticks) ->
receive
    done ->
        wait(N-1, Chopsticks);
    abort ->
        erlang:exit(abort)
end.

输出:

11> dinner:start().
<0.85.0>
12> 
=ERROR REPORT==== 10-Nov-2011::02:19:10 ===
 Error in process <0.85.0> with exit value: {undef,[{uniform,random,[500]}, {eater,dream,5},{dinner,init,0}]}

非常感谢,如果你读完所有这些,我还没有学会如何阅读erlang的错误报告。如果可以,并想告诉我这意味着什么,请做。

2 个答案:

答案 0 :(得分:8)

我认为问题在于您有三个模块:dinnereaterchopstick,但尝试在philospher:start中调用dinner:init/0功能。请改为eater:start

第二个问题是生成随机数时模块和函数名的顺序;将uniform:random替换为random:uniform中的eater.erl

1> dinner:start().
<0.35.0>
Confucios received a chopstick
Confucios received a chopstick
Confucios started eating
Confucios put back two chopsticks
Confucios received a chopstick
Confucios received a chopstick
Confucios started eating
Confucios put back two chopsticks
Confucios received a chopstick
Confucios received a chopstick
Confucios started eating
Confucios put back two chopsticks
Confucios received a chopstick
Confucios received a chopstick
Confucios started eating
Confucios put back two chopsticks
Confucios received a chopstick
Confucios received a chopstick
Confucios started eating
Confucios put back two chopsticks
Avicenna received a chopstick
Avicenna received a chopstick
Avicenna started eating
...

这很快就显示了第三个问题 - 我们应该从第一个错误报告中发现 - 食者实际上并不在他们自己的过程中。因此,请修改eater.erl,以便start()函数显示:

start(Hungry, Right, Left, Name, Ctrl) ->
    spawn_link(fun() -> dream(Hungry, Right, Left, Name, Ctrl) end).

现在它按预期工作:

1> dinner:start().
<0.35.0>
Confucios received a chopstick
Plato received a chopstick
Confucios received a chopstick
Confucios started eating
Descartes received a chopstick
Kant received a chopstick
Confucios put back two chopsticks
Avicenna received a chopstick
...

感谢。这很有趣。

答案 1 :(得分:2)

在您呼叫的任何地方进行更改: uniform:random/1 random:uniform/1 ,异常将消失