我不会尝试通过 Pid 访问子进程,而是在一个名称下注册/2子进程,因此无论实际的 Pid 是什么都可以访问它。
使用您引用的答案中的代码,一种简单的方法是添加register(ch1, self()),
到孩子的 init 过程中。这将为ch1.erl
:
init(_Args) ->
io:format("ch1 has started (~w)~n", [self()]),
% register a name to this process
register(child, self()),
{ok, ch1State}.
这会将孩子的 pid 注册self()
到 namechild
我们可以看到它的工作原理:
1> root_sup:start_link().
{ok,<0.34.0>}
2> supervisor:start_child(root_sup, []).
ch1 has started (<0.36.0>)
{ok,<0.36.0>}
3> lists:filter(fun(X) -> X == child end, registered()).
[child]
我们确实有一个以child
.
4> gen_server:cast(child, calc).
result 2+2=4
它是从ch1.erl
.
让我们通过调用错误代码来使这个过程崩溃:
5> gen_server:cast(child, calcbad).
result 1/0
ok
ch1 has started (<0.41.0>)
6>
=ERROR REPORT==== 28-Oct-2012::01:31:30 ===
** Generic server <0.36.0> terminating
** Last message in was {'$gen_cast',calcbad}
** When Server state == ch1State
** Reason for termination ==
** {'function not exported',
[{ch1,terminate,
[{badarith,
[{ch1,handle_cast,2,[{file,"ch1.erl"},{line,27}]},
{gen_server,handle_msg,5,
[{file,"gen_server.erl"},{line,607}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]},
ch1State],
[]},
{gen_server,terminate,6,[{file,"gen_server.erl"},{line,722}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,227}]}]}
于是孩子,进程<0.36.0>
崩溃了,一个新的孩子<0.41.0>
开始承担死者的职责<0.36.0>
。由于这个新进程以相同的名称注册,calc
将再次工作:
6> gen_server:cast(child, calc).
result 2+2=4
ok
请注意,这并不能保证gen_server:cast/2
s 总是导致相应代码的执行,因为子进程可能刚刚被杀死,而新进程仍未启动(实际上已注册)。
您可能想参考Joe Armstrong 撰写的优秀 Programming Erlang: Software for a Concurrent World,以了解有关进程注册、监督员、OTP 等的更多详细信息。许多细节也可以在OTP 的在线文档中找到。