代码之家  ›  专栏  ›  技术社区  ›  goncalotomas Lothar

为什么可以在Erlang中创建对同一进程的多个监视器引用?

  •  3
  • goncalotomas Lothar  · 技术社区  · 7 年前

    下面是一个示例跟踪,我可以调用 erlang:monitor/2 在同一Pid上:

    1> Loop = fun F() -> F() end.
    #Fun<erl_eval.30.99386804>
    2> Pid = spawn(Loop).
    <0.71.0>
    3> erlang:monitor(process, Pid).
    #Ref<0.2485499597.1470627842.126937>
    4> erlang:monitor(process, Pid).
    #Ref<0.2485499597.1470627842.126942>
    5> erlang:monitor(process, Pid).
    #Ref<0.2485499597.1470627842.126947>
    

    指令#4和#5返回的表达式与#3不同,这意味着可以在当前进程和 Pid . 是否存在需要或使用多个监视器引用同一流程的实际情况?

    我希望这将返回相同的引用(返回新引用可能意味着旧引用已失败/崩溃),遵循的逻辑与 link/1 .

    1 回复  |  直到 7 年前
        1
  •  5
  •   Hynek -Pichi- Vychodil Paulo Suassuna    7 年前

    假设您使用第三方库来实现这一点(基本上是OTP *:call/* 功能有):

    call(Pid, Request) ->
        call(Pid, Request, ?DEFAULT_TIMEOUT).
    
    call(Pid, Request, Timeout) ->
        MRef = erlang:monitor(process, Pid),
        Pid ! {call, self(), MRef, Request},
        receive
          {answer, MRef, Result} ->
            erlang:demonitor(Mref, [flush]),
            {ok, Result};
          {'DOWN', MRef, _, _, Info} ->
            {error, Info}
        after Timeout ->
            erlang:demonitor(MRef, [flush]),
            {error, timeout}
        end.
    

    然后在代码中使用它来监视同一进程 Pid 然后调用函数 call/2,3 .

    my_fun1(Service) ->
        MRef = erlang:monitor(process, Service),
        ok = check_if_service_runs(MRef),
        my_fun2(Service),
        mind_my_stuf(),
        ok = check_if_service_runs(MRef),
        erlang:demonitor(MRef, [flush]),
        return_some_result().
    
    check_if_service_runs(MRef) ->
        receive
          {'DOWN', MRef, _, _, Info} -> {down, Info}
        after 0 -> ok
        end.
    
    my_fun2(S) -> my_fun3(S).
    
    % and a many layers of other stuff and modules
    my_fun3(S) -> call(S, hello).
    

    如果 erlang:monitor/2,3 将始终返回相同的引用,如果 erlang:demonitor/1,2 将删除以前的监视器。这将是一个丑陋和无法解决的错误的来源。您应该开始认为有库、其他进程,您的代码是大型系统的一部分,而Erlang是由有经验的人精心设计的。可维护性是这里的关键。