环服务器消息没有遍历环

时间:2014-11-27 19:57:03

标签: process erlang server

我几乎已经实现了众所周知的铃声服务器,但是这些消息似乎并没有遍历铃声 - 这是我的代码:

module(ring).
-import(lists,[duplicate/2,append/1,zip/2,nthtail/2,nth/2,reverse/1]).
-export([start/3,server/0]).



start(M,N,Msg)->
    start(M,N,[],Msg).

start(0,0,_,_)->
    ok;
start(M,0,PList,Msg)->
    nth(1,PList)!nthtail(1,reverse(zip(append(duplicate(M,PList)),duplicate(M*length(PList),Msg))));
start(M,N,PList,Msg)->
    start(M,N-1,[spawn(ring, server, [])|PList],Msg).

server()-> 
    receive
        []->
            ok;
        [{Pid,Msg}|T]->
            io:format("~p,~p~n",[self(),Msg]),
            Pid!T;
        terminate->
            true
    end.

执行时返回以下内容:

2> ring:start(3,3,"hello").
<0.42.0>,"hello"
<0.41.0>,"hello"
[{<0.41.0>,"hello"},
 {<0.42.0>,"hello"},
 {<0.40.0>,"hello"},
 {<0.41.0>,"hello"},
 {<0.42.0>,"hello"},
 {<0.40.0>,"hello"},
 {<0.41.0>,"hello"},
 {<0.42.0>,"hello"}]

我可以问一下我在哪里错了吗?我已经检查了压缩的进程列表,看起来好像应该可以工作。提前谢谢。

2 个答案:

答案 0 :(得分:2)

这里有2个错误,主要是你在打印邮件后没有递归调用服务器。

第二个是你在构建第一条消息时不应该删除列表的头部,否则你只会传递m * n - 1条消息。

此代码有效,但它会使所有进程保持活动状态,您应该将其强化为在“响铃”结束时终止所有进程:

-module(ring).
-import(lists,[duplicate/2,append/1,zip/2,nthtail/2,nth/2,reverse/1]).
-export([start/3,server/0]).

start(M,N,Msg)->
    start(M,N,[],Msg).

start(0,0,_,_)->
    ok;
start(M,0,PList,Msg)->
    nth(1,PList)!reverse(zip(append(duplicate(M,PList)),duplicate(M*length(PList),Msg)));
start(M,N,PList,Msg)->
    start(M,N-1,[spawn(ring, server, [])|PList],Msg).

server()-> 
    receive
        []->
            ok;
        [{Pid,Msg}|T]->
            io:format("In Server ~p,~p~n",[self(),Msg]),
            Pid!T,
            server();
        terminate->
            true
    end.

在我这边,我不使用import,当我有列表时我发现​​它更明确:reverse ...,你可以使用hd / 1来获取列表的第一个元素,你可以使用list comprehension生成{Pid,Msg}

列表

答案 1 :(得分:1)

您的流程正在终止,而不是循环(并且永远不会有接收'terminate'的条件。要解决终止问题,请让他们spawn_link而不是spawn,这样当第一个死亡时,他们都会死亡。

最好通过自己发送信息来解决问题,以确保您不会完全剥离第一条消息。

-module(ring).
-import(lists,[duplicate/2,append/1,zip/2,nthtail/2,nth/2,reverse/1]).
-export([start/3,server/0]).

start(M, N, Msg)->
    Scroll = start(M, N, [], Msg),
    self() ! Scroll.

start(0, 0, _, _)->
    ok;
start(M, 0, PList, Msg)->
    nth(1, PList) ! nthtail(1, reverse(zip(append(duplicate(M, PList)),
    duplicate(M * length(PList), Msg))));
start(M, N, PList, Msg)->
    start(M, N - 1, [spawn_link(ring, server, []) | PList], Msg).

server()->
    receive
        []->
            ok;
        [{Pid, Msg} | T]->
            io:format("~p,~p~n", [self(), Msg]),
            Pid ! T,
            server()
    end.

这会产生:

1> c(ring).
{ok,ring}
2> ring:start(3,3,"raar!").
<0.42.0>,"raar!"
<0.41.0>,"raar!"
[{<0.41.0>,"raar!"},
 {<0.42.0>,"raar!"},
 {<0.40.0>,"raar!"},
 {<0.41.0>,"raar!"},
 {<0.42.0>,"raar!"},
 {<0.40.0>,"raar!"},
 {<0.41.0>,"raar!"},
 {<0.42.0>,"raar!"}]
<0.42.0>,"raar!"
<0.40.0>,"raar!"
<0.41.0>,"raar!"
<0.42.0>,"raar!"
<0.40.0>,"raar!"
<0.41.0>,"raar!"

正如所料。请注意,我在收到邮件时再次呼叫server()。当收到空列表时,它们都会因为链接而死亡。没有一团糟。

为了便于阅读,一些间距会更有礼貌。错误通常不会让我们想要通过大量的字符进行操作 - 这实际上会在某些边缘情况下(例如在地图语法中)导致一些运算符出错。此外,使用导入的功能还不太清楚。我知道用所有命名空间业务编写代码,但是当你开始编写更大的程序时它是一个救生员(erlang模块中有很多列表操作 - 所以有些导入是不必要的{ {3}})。