我几乎已经实现了众所周知的铃声服务器,但是这些消息似乎并没有遍历铃声 - 这是我的代码:
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"}]
我可以问一下我在哪里错了吗?我已经检查了压缩的进程列表,看起来好像应该可以工作。提前谢谢。
答案 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}})。