Erlang:尝试生成仅监视10个子进程的监视器集

时间:2014-11-16 23:22:15

标签: concurrency erlang

所以我们的想法是我们需要引入一些子进程来生成/监视,但是我们需要启动监视进程,这样它们一次只能处理少于10个子进程。因此,如果我们接受35个子进程,我们需要有4个监视器,3个监视10个孩子,还有一个监视5个。

问题在于,我正在努力弄清楚为什么我为此目的编写的代码失败了。这是代码:

-module(watcher).
-import(sensor, [start/0]).
-export([start/1, stop/0]).

start(NrSlaves) ->
    MasterPids = [],
    MasterPid = spawn(fun() -> master_starter(NrSlaves, MasterPids) end),
    register(master, MasterPid),
    ok.

stop() ->
    master ! die,
    ok.

slave_pid_to_nr(SlavePid, SlavePids) ->
    slave_pid_to_nr(SlavePid, SlavePids, 1).

slave_pid_to_nr(SlavePid, [SlavePid | _Tail], SlaveNr) ->
    SlaveNr;

slave_pid_to_nr(SlavePid, [_Head | Tail], SlaveNr) ->
    slave_pid_to_nr(SlavePid, Tail, SlaveNr + 1).

slave_change_pid(OldSlavePid, NewSlavePid, SlavePids) ->
    lists:map(
      fun(Pid) ->
          if
              Pid == OldSlavePid ->
                  NewSlavePid;
              true ->
                  Pid
          end
      end,
      SlavePids
    ).
%This is the part that errors out
master_starter(NrSlaves, MasterPids) ->
    if (NrSlaves/10) =< 1 ->
        MasterPids = MasterPids ++ [spawn_link(fun() -> master_start(NrSlaves) end)];
    true->
        MasterPids = MasterPids ++ [spawn_link(fun() -> master_start(10) end) || lists:seq(1, (NrSlaves/10))],
        master_starter(NrSlaves-10, MasterPids)
    end,

    receive
        die ->
            io:fwrite("Monitor: received die~n"),
            lists:foreach(fun(MasterPid) -> MasterPid ! die end, MasterPids)
    end.

master_start(NrSlaves) ->
    process_flag(trap_exit, true),
    io:fwrite("monitor: started~n", []),
    SlavePids = [spawn_link(fun() -> slave_start(SlaveNr) end) || SlaveNr <- lists:seq(1, NrSlaves)],
    master_loop(SlavePids).

master_loop(SlavePids) ->
    receive
        die ->
            io:fwrite("Monitor: received die~n"),
            lists:foreach(fun(SlavePid) -> SlavePid ! die end, SlavePids);
        {SlaveNr, Measurement} ->
            io:fwrite("Sensor# ~p measures ~p~n", [SlaveNr, Measurement]),
            master_loop(SlavePids);
        {'EXIT', SlavePid, _Reason} ->
            SlaveNr = slave_pid_to_nr(SlavePid, SlavePids),
            io:fwrite("Monitor: Sensor ~p with PID ~p died because of a crash~n", [SlaveNr, SlavePid]),
            NewSlavePid = spawn_link(fun() -> slave_start(SlaveNr) end),
            NewSlavePids = slave_change_pid(SlavePid, NewSlavePid, SlavePids),
            master_loop(NewSlavePids)
    end.

slave_start(SlaveNr) ->
    % SlavePid = lists:nth(SlaveNr, SlavePids),
    io:fwrite("sensor ~p with PID ~p: started~n", [SlaveNr, self()]),
    %%slave_loop(SlaveNr).
    sensor:start(SlaveNr).

我收到的错误如下:&#34;流程错误&lt; 0.573.0&gt;退出值:{{badmatch,[&lt; 0.574.0&gt;]},[{watcher,master_starter,2,[{file,&#34; watcher.erl&#34;},{line,39}]}] }&#34;

任何帮助将不胜感激。它已经非常接近完成,但我只需要理解为什么它不起作用。

2 个答案:

答案 0 :(得分:1)

我在您的代码中看到了三个问题。

变量是不可变的,MasterPids = MasterPids ++ ...将失败并出现badmatch错误。尝试分配新变量,例如NewPidsMasterPids2

您在列表理解中缺少生成器。你应该在那里<-[spawn_link( ... ) || _ <- lists:seq(1, (NrSlaves/10)).

lists:seq不接受浮动。您必须将NrSlaves/10向上舍入为整数。您可以使用ceiling function from here(可能会稍微简化,因为您不会使用负数)。

答案 1 :(得分:0)

变量在erlang中不可变。所以

MasterPids = MasterPids ++ [spawn_link(fun() -> master_start(NrSlaves) end)];
由于您尝试修改MasterPids

将失败