Erlang失败的范围

时间:2014-12-08 22:43:57

标签: erlang

如果我有两个Erlang模块:A和B,取消链接。

在A:

 start() -> register(A, spawn_link(A,init,[])).

 init() -> loop().

 loop() ->
    receive
        {request, call_B} -> B:method(),
        loop()
    end.

 call_method() -> A !  {request, call_B}.

在B:

 start() -> register(B, spawn_link(B,init,[])).

 init() -> loop().

 loop() ->
  receive
   {request, do} -> do_something...,
   loop()
  end.

 method() -> B ! {request, do}.

然后在shell中:

 A:start(),
 B:start(),
 A:call_method().

现在,do_something有一个例外,所以B死了。在这种情况下,A也会死吗?

我试图在shell中启动A然后杀死A.并且确实重新启动了shell。我能否根据这种行为得出上述问题的答案是肯定的?

2 个答案:

答案 0 :(得分:3)

我认为,你是令人困惑的流程和模块,这很常见,我甚至blogged about it。我的博客上的示例显示,在一个模块中,您可以拥有在两个进程中运行的代码。通常你有。

没有'链接模块'这样的东西。只能链接进程

所以在你的例子中。所以在你的例子中:

  • 你有一个shell进程
  • 您生成进程A,它使用模块A中的循环并链接到shell
  • 您生成进程B,它使用来自模块B的循环,并且还链接到shell
  • 您发送邮件给流程A以致电B:method

现在是棘手的部分:如果method是这样的话:

method() ->
    1 / 0.

它仍在进程A中调用,进程A死掉。 它链接到shell,所以shell die和shell链接到B,所以B死掉了。 (我假设你没有陷阱存在)。

但通常method是这样的:

method() ->
    B ! do_something.

然后,B会崩溃,它会使shell崩溃,这会导致A崩溃。你可以通过在其中一个进程上设置trap_exit标志来打破链。例如关于shell进程。在你的shell中试试这个:

process_flag(trap_exit, true). % don't crash shell, when linked process dies
spawn_link(fun() -> 1/0 end).  % spawn_link process, that dies
flush().                       % shell did not die - it got message, that you can view with flush/0

答案 1 :(得分:1)

链接是双向的。当您在A和B之间创建链接以及A和C之间的链接时,它们都在相同的“失败范围”内。 相同的退出消息不会传播到所有链接,但每个链接都是“EXIT”消息传播的通道。如果B崩溃,它会向A发送一个出口,因此它会崩溃,当它崩溃时会向C发送一个出口。这种链接可以任意长或宽

陷阱退出的进程会中断此传播,并将其收到的任何“EXIT”消息视为消息,而不是表示它也应该崩溃。

您可以使用链接创建任何类型的图形形状(理解它们是双向,当然 - 制作一个循环图,您需要监视器,这是单向的),但是大多数情况下,Erlang程序是在树中设计的,其中出口陷阱仅在主管的树根附近进行。

只是为了好玩,这里是一个崩溃在shell中传播的插图:

1> register(foo, spawn_link(fun() -> receive M -> io:format("~p~n", [M]) end end)).
true
2> register(bar, spawn_link(fun() -> receive M -> io:format("~p~n", [M]) end end)). 
true
3> exit(whereis(bar), kill).
** exception exit: killed
4> foo ! hey.
** exception error: bad argument
     in operator  !/2
        called as foo ! hey

首先,我们生成两个进程,注册为'foo'和'bar',它们都链接到shell。他们所做的只是等待重复一些信息。在向他们发送任何消息之前,我们残忍地谋杀了“酒吧”。 'bar的退出消息被发送到shell,因此shell在第3行之后死亡并由其主管重新启动(因此我们在第4行得到提示)。 'foo'还活着吗?我们尝试向它发送一条消息,却发现它已经不存在了!当shell崩溃时,它向其所有链接进程发送了一条退出消息,'foo'就是其中之一(shell主管是另一个)。 'foo'没有捕获退出,所以它已经死了,但shell的主管正在捕获退出,因此收到了一条消息{'EXIT', Proc, Reason}(shell的主管知道它是shell并且需要重新启动,并且这样做了)