【问题标题】:correct usage of erlang spawn_monitorerlang spawn_monitor 的正确使用
【发布时间】:2026-01-19 07:45:02
【问题描述】:

仍在阅读 Joe 的书,很难完全理解监视器,尤其是 spawn_monitor。这是我的代码;练习要求编写一个函数,该函数将启动一个进程,其工作是每 5 秒打印一次心跳,然后编写一个函数来监视上述进程并重新启动它。我没有进入重启部分,因为我的监视器甚至无法检测到进程崩溃。

% simple "working" loop
loop_5_print() ->
    receive
    after 5000 ->
            io:format("I'm still alive~n"),
            loop_5_print()
    end.

% function to spawn and register a named worker
create_reg_keep_alive(Name) when not is_atom(Name) ->
    {error, badargs};
create_reg_keep_alive(Name) ->
    Pid = spawn(ex, loop_5_print, []),
    register(Name, Pid),
    {Pid, Name}.

% a simple monitor loop
monitor_loop(AName) ->
    Pid = whereis(AName),
    io:format("monitoring PID ~p~n", [Pid]),
    receive
        {'DOWN', _Ref, process, Pid, Why} ->
            io:format("~p died because ~p~n",[AName, Why]),
            % add the restart logic
            monitor_loop(AName)
    end.

% function to bootstrapma monitor
my_monitor(AName) ->
    case whereis(AName) of
        undefined -> {error, no_such_registration};

        _Pid -> spawn_monitor(ex, monitor_loop, [AName])
    end.

这是我在玩的:

39> c("ex.erl").                    
{ok,ex}
40> ex:create_reg_keep_alive(myjob).
{<0.147.0>,myjob}
I'm still alive                     
I'm still alive          
41> ex:my_monitor(myjob).
monitoring PID <0.147.0>
{<0.149.0>,#Ref<0.230612052.2032402433.56637>}
I'm still alive
I'm still alive                     
42> exit(whereis(myjob), stop).
true
43> 

它确实停止了 loop_5_print “worker” - 但是监视器应该打印的行在哪里? 我看到的唯一解释是发出的消息以这种方式退出的进程不是我在监视器循环的 receive 中匹配的模式。但这是本书在本章中介绍的唯一模式,所以我不买这个解释..

【问题讨论】:

    标签: erlang


    【解决方案1】:

    spawn_monitor 不是你想要的。 spawn_monitor 产生一个进程并立即开始监视它。当生成的进程死亡时,调用spawn_monitor 的进程会收到一条消息,表明该进程已死亡。您需要从要接收 DOWN 消息的进程中调用 erlang:monitor/2,第二个参数是要监控的 Pid。

    只需添加:

    monitor(process, Pid),
    

    之后:

    Pid = whereis(AName),
    

    它的工作原理:

    1> c(ex).
    {ok,ex}
    2> ex:create_reg_keep_alive(myjob).
    {<0.67.0>,myjob}
    I'm still alive
    I'm still alive
    I'm still alive
    3> ex:my_monitor(myjob).
    monitoring PID <0.67.0>
    {<0.69.0>,#Ref<0.2696002348.2586050567.188678>}
    I'm still alive
    I'm still alive
    I'm still alive
    4> exit(whereis(myjob), stop).
    myjob died because stop
    true
    monitoring PID undefined
    

    【讨论】:

    • 天哪,你说得对。我一直对监视器语义感到困惑;我已经意识到 spawn_monitor/3 并不意味着“创建一个监视器”,而是“创建这个计算并监控它”——但我在没有意识到的情况下又回到了我的误解。跨度>
    • 再次感谢队友-您指出了我的错误,我能够修复,然后重构我的解决方案;我觉得 Erlang foo 在我身上变得越来越强大 =)