How to tell a process to create another process and keep track of it

distributed, erlang

Solution

Okay. Now, for purposes of learning, lets do a very basic example. Others will talk of `OTP Supervisors, Process dictionaries` e.t.c. but i want to keep it easy for learning purposes. With tis example, the generator can know how many processes it has created, their `Pids`, knows when they die e.t.c.

-module(generator).
-compile(export_all).
-define(ERROR(X),error_logger:error_report(X)).
start()->
    register(generator,spawn(fun() -> generator() end)),
    ok.
generator()->
    ProcessBuffer = [],
    process_flag(trap_exit,true),
    loop(ProcessBuffer).
create(Module,Function,Args)->
    generator ! {create_new_proc,{Module,Function,Args}},
    ok. 
send_to_kids(Message)->
    generator ! {tell_kids,Message},
    ok. 
loop(Buffer)->
    receive
        {create_new_proc,{M,F,A}} ->
            Pid = spawn(M,F,A),
            link(Pid),
            loop([Pid|Buffer]);
        {tell_kids,Message} ->
            [ Kid ! {broadcast,Message} || Kid <- Buffer],
            loop(Buffer);
        {'EXIT',SomePid,Reason} ->
            ?ERROR(["Child has crashed",{pid,SomePid},{reason,Reason}]),
            loop(lists:delete(SomePid,Buffer));
        _ -> loop(Buffer)
    end.
child_loop()->
    receive
        {broadcast,Message} -> 
            io:format("\n\tChild: ~p got: ~p~n",[self(),Message]),
            child_loop();
        _ -> child_loop()
    end.

Testing in shell

E:\Applications>erl
Eshell V5.9  (abort with ^G)
1> c(generator).
{ok,generator}
2> generator:start().
ok
3> generator:create(generator,child_loop,[]).
ok
4> [generator:create(generator,child_loop,[]) || _ <- lists:seq(1,5)],ok.
ok
5> generator:send_to_kids("Erlang is good !").
        Child: <0.45.0> got: "Erlang is good !"
        Child: <0.44.0> got: "Erlang is good !"
        Child: <0.43.0> got: "Erlang is good !"
        Child: <0.42.0> got: "Erlang is good !"
        Child: <0.41.0> got: "Erlang is good !"
        Child: <0.39.0> got: "Erlang is good !"
ok
6> generator:send_to_kids("1+1 = 2").
        Child: <0.45.0> got: "1+1 = 2"
        Child: <0.44.0> got: "1+1 = 2"
        Child: <0.43.0> got: "1+1 = 2"
        Child: <0.42.0> got: "1+1 = 2"
        Child: <0.41.0> got: "1+1 = 2"
        Child: <0.39.0> got: "1+1 = 2"
ok
7>

A process registered as `generator` is started and may be told to start any number of children processes. The child process is generically created from the `{M, F, A}` combination sent to the `generator`. The generator loop keeps a track record of the processes created. It can then be told to broadcast messages to all processes. However, in practice/ production, you might not to do this, because the `generator` loop may consume lots of memory as the list `Buffer` grows since thats where we keep all the `Pids` of our processes. You can also use `ETS Tables`, or `Mnesia` e.t.c but i havenot used them in the example because they will seem a little bit more advanced. Look at this question and its answer to understand more.

Problem

How can I tell a specific process (let's call it the generator) to create a new process in Erlang? Also, how can I keep track of all the processes that the generator has created?

Original source

Related problems