简体   繁体   English

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

[英]Why can you create multiple monitor references to the same process in Erlang?

Here is an example trace where I'm able to call erlang:monitor/2 on the same Pid: 这是一个示例跟踪,我可以在同一个Pid上调用erlang:monitor/2

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>

The expressions returned by instruction #4 and #5 are different than #3, meaning that it is possible to create multiple monitor references between the current process and Pid . 指令#4和#5返回的表达式与#3不同,这意味着可以在当前进程和Pid之间创建多个监视器引用。 Is there a practical case where you would need or use multiple monitor references to the same process? 是否存在需要或使用同一进程的多个监视器引用的实际案例?

I would expect this to return the same reference (returning a new one would perhaps imply that the old one had failed/crashed), following the same logic that exists for link/1 . 我希望这会返回相同的引用(返回一个新的可能意味着旧的一个失败/崩溃),遵循与link/1相同的逻辑。

Imagine you use third party library which does this (basically what OTP *:call/* functions does): 想象一下,您使用第三方库来执行此操作(基本上是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.

and then you use it in your code where you would monitor the same process Pid and then call function call/2,3 . 然后你在你的代码中使用它,你将监视相同的进程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).

What a nasty surprise it would be if erlang:monitor/2,3 would always return the same reference and if erlang:demonitor/1,2 would remove your previous monitor. 如果erlang:monitor/2,3总会返回相同的引用,如果erlang:demonitor/1,2会删除你以前的显示器,那将是多么令人讨厌的惊喜。 It would be a source of ugly and unsolvable bugs. 它将是丑陋和无法解决的错误的来源。 You should start to think that there are libraries, other processes, your code is part of a huge system and Erlang was made by experienced people who thought it through. 您应该开始认为有库,其他进程,您的代码是庞大系统的一部分,而Erlang是由经验丰富的人制作的。 Maintainability is key here. 可维护性是关键。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM