【问题标题】:Erlang pids from console来自控制台的 Erlang pid
【发布时间】:2012-10-17 18:15:30
【问题描述】:

我看到了消息:

https://stackoverflow.com/a/4837832/1236509

与主管:

-module(root_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).

start_link() ->
     {ok, Pid} = supervisor:start_link({local, ?MODULE}, 
          ?MODULE, []),
     erlang:unlink(Pid),
     {ok, Pid}.

init(_Args) ->
     RestartStrategy = {simple_one_for_one, 10, 60},
     ChildSpec = {ch1, {ch1, start_link, []},
          permanent, brutal_kill, worker, [ch1]},
     Children = [ChildSpec],
     {ok, {RestartStrategy, Children}}.

在控制台人员调用中:

{ok, ChildPid1} = root_sup:start_link().

当子 pid 更改时,ChildPid1 将如何获得新的 pid,以便始终可以将 ChildPid1 与正确的 pid 一起使用?需要链接到创建孩子的主管的一部分。

【问题讨论】:

    标签: erlang


    【解决方案1】:

    我不会尝试通过 Pid 访问子进程,而是 register/2 使用名称的子进程,因此无论实际 Pid 是什么都可以访问它。

    使用代码from the answer you reference,一个简单的方法是将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}.
    

    这会将孩子self() 的pid 注册到名称child 我们可以看到它有效:

    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}]}]}
    

    于是孩子,进程&lt;0.36.0&gt;崩溃了,一个新的孩子&lt;0.41.0&gt;开始承担死者&lt;0.36.0&gt;的职责。由于这个新进程以相同的名称注册,calc 将再次工作:

    6> gen_server:cast(child, calc).   
    result 2+2=4
    ok
    

    请注意,这并不能保证gen_server:cast/2s 总是导致相应代码的执行,因为可能刚刚杀死了子进程,而新进程仍未启动(实际上已注册)。

    您可能想参考优秀的Programming Erlang: Software for a Concurrent World by Joe Armstrong,了解有关流程注册、主管、OTP 等的更多详细信息。很多细节也可以在the online documentation of OTP找到。

    【讨论】:

    • 当子pid发生变化时,是因为进程已经死亡,所以name会不会也指向子进程中断?
    • 实际上,是的,在崩溃和重启之间,发送给孩子的消息将会丢失。
    • 我看不出这对 Child1Pid 的值有何影响?
    • 谢谢,但我想更新 Child1Pid 以便在控制台传递给子函数?
    • 通常使用简单的一对一策略来按需启动流程。因此,应用程序生命周期内的进程数是未知的。出于这个原因,我认为在这种情况下注册孩子不是一个好主意。根据您想要做什么,您可以要求主管获取活动进程的列表,或者从将运行进程列表保存在其状态变量中的服务器启动它们。
    猜你喜欢
    • 1970-01-01
    • 2018-10-11
    • 2016-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多