Concurrency 我能在Erlang找到一个外部出口吗?

Concurrency 我能在Erlang找到一个外部出口吗?,concurrency,erlang,try-catch,exit,Concurrency,Erlang,Try Catch,Exit,我有两个过程相联系;假设它们是A和B,其中A设置为陷阱出口。如果有人调用exit/2,例如exit(B,diedie),我希望能够恢复B的一段流程数据 在B的模块中,我们称之为bmod.erl,我有一些代码如下所示: -module(bmod). -export([b_start/2]). b_start(A, X) -> spawn(fun() -> b_main(A, X) end). b_main(A, X) -> try A !

我有两个过程相联系;假设它们是
A
B
,其中
A
设置为陷阱出口。如果有人调用
exit/2
,例如
exit(B,diedie)
,我希望能够恢复
B
的一段流程数据

B
的模块中,我们称之为
bmod.erl
,我有一些代码如下所示:

-module(bmod).
-export([b_start/2]).

b_start(A, X) ->
    spawn(fun() -> b_main(A, X) end).

b_main(A, X) ->
      try
        A ! {self(), doing_stuff},
        do_stuff()
      catch
        exit:_ -> exit({terminated, X})
      end,
      b_main(A, X).

do_stuff() -> io:format("doing stuff.~n",[]).
-module(amod).
-export([a_start/0]).

a_start() ->
  process_flag(trap_exit, true),
  link(bmod:b_start(self(), some_stuff_to_do)),
  a_main().

a_main() ->
  receive
    {Pid, doing_stuff} ->
      io:format("Process ~p did stuff.~n",[Pid]),
      exit(Pid, diediedie),
      a_main();
    {'EXIT', Pid, {terminated, X}} ->
      io:format("Process ~p was terminated, had ~p.~n", [Pid,X]),
      fine;
    {'EXIT', Pid, _Reason} ->
      io:format("Process ~p was terminated, can't find what it had.~n", [Pid]),
      woops
  end.
A
的模块中,我们称之为
amod.erl
,我有一些代码如下所示:

-module(bmod).
-export([b_start/2]).

b_start(A, X) ->
    spawn(fun() -> b_main(A, X) end).

b_main(A, X) ->
      try
        A ! {self(), doing_stuff},
        do_stuff()
      catch
        exit:_ -> exit({terminated, X})
      end,
      b_main(A, X).

do_stuff() -> io:format("doing stuff.~n",[]).
-module(amod).
-export([a_start/0]).

a_start() ->
  process_flag(trap_exit, true),
  link(bmod:b_start(self(), some_stuff_to_do)),
  a_main().

a_main() ->
  receive
    {Pid, doing_stuff} ->
      io:format("Process ~p did stuff.~n",[Pid]),
      exit(Pid, diediedie),
      a_main();
    {'EXIT', Pid, {terminated, X}} ->
      io:format("Process ~p was terminated, had ~p.~n", [Pid,X]),
      fine;
    {'EXIT', Pid, _Reason} ->
      io:format("Process ~p was terminated, can't find what it had.~n", [Pid]),
      woops
  end.
(我意识到我应该正常地执行
spawn\u link
,但在我的原始程序中,spawn和link之间有代码,因此我以这种方式对示例代码进行建模。)

现在当我运行代码时,我得到了这个

2> c(amod).
{ok,amod}
3> c(bmod).
{ok,bmod}
4> amod:a_start().
doing stuff.
Process <0.44.0> did stuff.
doing stuff.
Process <0.44.0> did stuff.
Process <0.44.0> was terminated, can't find what it had.
woops
5> 
2>c(amod)。
{好的,阿莫德}
3> c(bmod)。
{好的,bmod}
4> amod:a_start()。
做事。
这个过程做了很多事情。
做事。
这个过程做了很多事情。
进程已终止,无法找到它所拥有的内容。
呜呜声
5> 
如何获取
b_main()
来捕获此外部出口,以便它可以报告其状态
X

对于
b_main()
要捕获外部出口,它必须通过调用
进程\u标志(trap_exit,true)
来捕获出口。这将向进程发送一条消息,在该消息中,进程可以退出,状态为
X
。代码如下

b_start(A, X) ->
    spawn(fun() -> process_flag(trap_exit, true), b_main(A, X) end).

b_main(A, X) ->
    try
        A ! {self(), doing_stuff},
        do_stuff()
    catch
        exit:_ -> 
            io:format("exit inside do_stuff() . ~n"),
            exit({terminated, X})
    end,

    receive
        {'EXIT',Pid, Reason} ->
            io:format("Process received exit ~p ~p.~n",[Pid, Reason]),
            exit({terminated, X})
    after 0 ->
            ok
    end,
    b_main(A, X).
对于
b_main()
要捕获外部出口,它必须通过调用
process_标志(trap_exit,true)
捕获出口。这将向进程发送一条消息,在该消息中,进程可以退出,状态为
X
。代码如下

b_start(A, X) ->
    spawn(fun() -> process_flag(trap_exit, true), b_main(A, X) end).

b_main(A, X) ->
    try
        A ! {self(), doing_stuff},
        do_stuff()
    catch
        exit:_ -> 
            io:format("exit inside do_stuff() . ~n"),
            exit({terminated, X})
    end,

    receive
        {'EXIT',Pid, Reason} ->
            io:format("Process received exit ~p ~p.~n",[Pid, Reason]),
            exit({terminated, X})
    after 0 ->
            ok
    end,
    b_main(A, X).

简短的回答是:您应该在
b_main/2
中执行
trap_exit
,并接收
{'exit',…}
消息。就在我尝试之前,@vinod就概述了这一点。一、 相反,我将尝试解释一些正在发生的事情

如果进程正在捕获退出,并且它即将死亡,例如,当有人调用
exit(Pid,die)
或某个链接的进程以
exit(die)
结束时,它将在其邮箱中获得
{'exit',…}
消息,而不是出于同样的原因静默死亡。是运行时系统向每个链接的进程发出退出信号,人们可以捕获它而不是死亡

此规则的唯一例外是当发出
exit(Pid,kill)
调用时,那么无论进程是否正在捕获退出,它都会因为原因而死亡
kill

因此,为了避免外部出口信号导致的无声死亡,该过程必须捕获出口。同样,如果流程想知道与他有关联的人为什么刚刚死亡并采取一些措施恢复,那么该流程必须阻止退出。每个被捕获的退出信号在进程邮箱中显示为消息

因此,您的
尝试没有效果。。。catch exit:->…
关于捕获出口的语句

通常情况下,
trap\u exit
被视为不良做法。有一个简单的例子说明了原因:

18> self().
<0.42.0>
19> Pid = spawn_link(fun () -> process_flag(trap_exit, true), 
  Loop = fun (F) -> receive Any -> io:format("Any: ~p~n", [Any]) end, F(F) end, 
    Loop(Loop) end).
<0.58.0>
20> exit(Pid, grenade).                                         
Any: {'EXIT',<0.42.0>,grenade}
true
21> exit(Pid, grenade).
Any: {'EXIT',<0.42.0>,grenade}
true
...
18>self()。
19> Pid=spawn_链接(fun()->进程_标志(陷阱_退出,真),
Loop=fun(F)->receive Any->io:format(“Any:~p~n,[Any])end,F(F)end,
循环(循环)结束)。
20> 出口(Pid,手榴弹)。
任何:{'EXIT',手榴弹}
真的
21>退出(Pid,手榴弹)。
任何:{'EXIT',手榴弹}
真的
...
正如您可能看到的,某些进程被链接,正在捕获退出并拒绝正常退出。这是出乎意料的,显然是潜在的危险。由于链接是可传递的,因此它可能会中断发送给一组链接进程的出口链


这里有许多微妙的特性,它们被完美地展现出来。

简单的回答是:你应该在
b_main/2中执行
trap_exit
,并接收
{'exit',…}
消息。就在我尝试之前,@vinod就概述了这一点。一、 相反,我将尝试解释一些正在发生的事情

如果进程正在捕获退出,并且它即将死亡,例如,当有人调用
exit(Pid,die)
或某个链接的进程以
exit(die)
结束时,它将在其邮箱中获得
{'exit',…}
消息,而不是出于同样的原因静默死亡。是运行时系统向每个链接的进程发出退出信号,人们可以捕获它而不是死亡

此规则的唯一例外是当发出
exit(Pid,kill)
调用时,那么无论进程是否正在捕获退出,它都会因为原因而死亡
kill

因此,为了避免外部出口信号导致的无声死亡,该过程必须捕获出口。同样,如果流程想知道与他有关联的人为什么刚刚死亡并采取一些措施恢复,那么该流程必须阻止退出。每个被捕获的退出信号在进程邮箱中显示为消息

因此,您的
尝试没有效果。。。catch exit:->…
关于捕获出口的语句

通常情况下,
trap\u exit
被视为不良做法。有一个简单的例子说明了原因:

18> self().
<0.42.0>
19> Pid = spawn_link(fun () -> process_flag(trap_exit, true), 
  Loop = fun (F) -> receive Any -> io:format("Any: ~p~n", [Any]) end, F(F) end, 
    Loop(Loop) end).
<0.58.0>
20> exit(Pid, grenade).                                         
Any: {'EXIT',<0.42.0>,grenade}
true
21> exit(Pid, grenade).
Any: {'EXIT',<0.42.0>,grenade}
true
...
18>self()。
19> Pid=spawn_链接(fun()->进程_标志(陷阱_退出,真),
Loop=fun(F)->receive Any->io:format(“Any:~p~n,[Any])end,F(F)end,
循环(循环)结束)。
20> 出口(Pid,手榴弹)。
任何:{'EXIT',手榴弹}
真的
21>退出(Pid,手榴弹)。
任何:{'EXIT',手榴弹}
真的
...
正如您可能看到的,某些进程被链接,正在捕获退出并拒绝正常退出。这是出乎意料的,显然是潜在的危险。由于链接是可传递的,因此它可能会中断发送给一组链接进程的出口链


这里有许多微妙的特长,它们被完美地展现出来。

我真的很喜欢这个解释@vinod的代码很棒,但知道发生了什么对我的原始程序有很大帮助@vinod的代码很棒,但知道什么是