1

I saw message:

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

with supervisor:

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

In console man calls:

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

when child pid changes how would ChildPid1 get new pid so always can use ChildPid1 with correct pid? Need way to link to part of supervisor creating child.

Community
  • 1
  • 1
Lethi
  • 1,167
  • 1
  • 10
  • 16

1 Answers1

1

I would not try to access the child by Pid but instead register/2 the child process under a name, so it's accessible regardless of the actual Pid.

Using the code from the answer you reference, a simple way of doing this is to add register(ch1, self()), to the init procedure of the child. This would give, for ch1.erl:

init(_Args) ->
     io:format("ch1 has started (~w)~n", [self()]),
     % register a name to this process
     register(child, self()),
     {ok, ch1State}.

This registers the pid of the child self() to the name child We can see it works:

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]

we indeed have a process registered under the name of child.

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

and it is a correct process running the code from ch1.erl.

Let us crash this process, by invoking the bad code:

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

So the child, the process <0.36.0> crashed, and a new child <0.41.0> was started to assume the duties of the deceased <0.36.0>. Since this new process is registered under the same name, calc will work again:

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

Note that this does not guarantee that the gen_server:cast/2s always result in the execution of the corresponding code because the child might have been killed just now and the new process still was not started (registered in fact).

You might want to refer to the excellent Programming Erlang: Software for a Concurrent World by Joe Armstrong for more details about process registration, supervisors, OTP and more. Many details can also be found in the online documentation of OTP.

Community
  • 1
  • 1
bernard paulus
  • 1,644
  • 1
  • 21
  • 33
  • when the child pid changes, it because process has died, so wont name point to child process break also? – Lethi Oct 27 '12 at 22:49
  • actually, yeah, between the crash and a restart, messages sent to the child will be lost. – bernard paulus Oct 27 '12 at 22:59
  • I not see how this make any difference to value of Child1Pid? – Lethi Oct 27 '12 at 23:26
  • Thank you but I want update Child1Pid so I can pass in to child functions at console? – Lethi Oct 27 '12 at 23:40
  • You cannot update variables in Erlang, and although counter-intuitive, this is a strength of Erlang: without any "memory device" (be it a normal C/java/Python variable, access to another process or IO device), a function always returns the same value given the same input. And this facilitates greatly the debugging. – bernard paulus Oct 27 '12 at 23:50
  • To be complete: there is a way to update a value in erlang without interacting with another process or performing some IO: the process dictionary. Using this, however, is strongly discouraged, because you lose the above property of determinism (always same return with same input). – bernard paulus Oct 27 '12 at 23:57
  • 2
    Generally the simple-one-for-one strategy is used to launch processes on demand. So the number of processes during the application lifetime is not known. For this reason I don't think that it is a good idea to register the children in this case. Depending on what you want to do, you can ask the supervisor to get the list of active processes, or launch them from a server that keep a list of the running processes in its state variable. – Pascal Oct 28 '12 at 19:29
  • You are right, thank you! A call to [supervisor:which_children/1](http://www.erlang.org/doc/man/supervisor.html#which_children-1) is a way better solution. I got fixated on `always can use ChildPid1` and thus wrongly assumed a single supervised process. – bernard paulus Oct 28 '12 at 20:01
  • I see which_children() before posting. Problem is how I know which_child() give me one I want? What I use to identify the child? I mean, if child pid changes and I only have old pid, how can which_children() help? old pid will not help me? – Lethi Oct 28 '12 at 20:04
  • we are using a `simple_one_for_one` restart strategy. This has the particularity of only allowing to have children of [the same kind](http://learnyousomeerlang.com/supervisors#using-supervisors), so any of the Pid returned should be good. Try, with the original code (without the `register`): `root_sup:start_link(), supervisor:start_child(root_sup, []), supervisor:which_children(root_sup).` This will return a list containing (among other things) the Pid of the child. – bernard paulus Oct 28 '12 at 20:47