Muzaaya Joshua
Muzaaya Joshua

Reputation: 7836

"How many links do I have?", asks an Erlang process

A process in Erlang will either call link/1 or spawn_link to create a link with another process. In a recent application i am working on i got curious on whether its possible for a process to know at a given instance, the number of other processes its linked to. is this possible ? is their a BIF ?

Then, also, when a linked process dies, i guess that if it were possible to know the number of linked processes, this number would be decremented automatically by the run-time system. Such a mechanism would be ideal in dealing with Parent-Child relationships in Erlang concurrent programs, even in simple ones which do not involve supervisors.

Well, is it possible for an Erlang process to know out-of-the-box perhaps via a BIF, the number of processes linked to it, such that whenever a linked process dies, this value is decremented automatically under-the-hood :)?


To expand on this question a little bit, consider a gen_server, which will handle thousands of messages via handle_info. In this part, its job is to dispatch child processes to handle the task as soon as it comes in. The aim of this is to make sure the server loop returns immediately to take up the next request. Now, the child process handles the task asynchronously and sends the reply back to the requestor before it dies. Please refer to this question and its answer before you continue.

Now, what if, for every child process spawned off by the gen_server, a link is created, and i would like to use this link as a counter. I know, i know, everyone is going to be like " why not use the gen_server State, to carry say, a counter, and then increment or decrement it accordingly ? " :) Somewhere in the gen_server, i have:

handle_info({Sender,Task},State)->
    spawn_link(?MODULE,child,[Sender,Task]),
    %%  At this point, the number of links to the gen_server is incremented
    %%  by the run-time system
    {noreply,State};
handle_info( _ ,State) -> {noreply,State}.

The child goes on to do this:

child(Sender,Task)->
    Result = (catch execute_task(Task)),
    Sender ! Result,
    ok. %% At this point the child process exits, 
        %% and i expect the link value to be decremented

Then finally, the gen_server has an exposed call like this:

get_no_of_links()-> gen_server:call(?MODULE,links).
handle_call(links, _ ,State)->
    %% BIF to get number of instantaneous links expected here
    Links = erlang:get_links(), %% This is fake, do not do it at home :)
    {reply,Links,State};
handle_call(_ , _ ,State)-> {reply,ok,State}.

Now, some one may ask them selves, really, Why would anyone want to do this ?

Usually, its possible to create an integer in the gen_server State and then we do it ourselves, or at least make the gen_server handle_info of type {'EXIT',ChildPid,_Reason} and then the server would act accordingly. My thinking is that if it were possible to know the number of links, i would use this to know ( at a given moment in time), how many child processes are still busy working, this in turn may actually assist in anticipating server load.

Upvotes: 3

Views: 1506

Answers (2)

r3m0t
r3m0t

Reputation: 1870

Your process should run process_flag(trap_exit, true) and listen for messages of the form {'EXIT', Pid, Reason} which will arrive whenever a linked process exits. If you don't trap exits, the default behaviour will be for your linked process to exit when the other side of the link exits.

As for listening to when processes add links, you can use case process_info(self(), links) of {links, L} -> length(L) end or length(element(2, process_info(self(), links)), but you have to re-run this regularly as there is no way for your process to be notified whenever a link is added.

A process following OTP guidelines never needs to know how many processes are linked to it.

Upvotes: 1

user1806568
user1806568

Reputation:

From manual for process_info:

{links, Pids}: Pids is a list of pids, with processes to which the process has a link

3> process_info(self(), links).
{links,[<0.26.0>]}
4> spawn_link(fun() -> timer:sleep(100000) end).
<0.38.0>
5> process_info(self(), links).                 
{links,[<0.26.0>,<0.38.0>]}

I guess it could be used to count number of linked processes

Upvotes: 8

Related Questions