Question

I have two gen_server modules.
First serv.erl

-module(serv).
-behaviour(gen_server).
-export([init/1, 
     handle_call/3,
     handle_cast/2, 
     handle_info/2,
     code_change/3,
     terminate/2,
     start_link/0
    ]).
start_link() ->
    gen_server:start_link(?MODULE, [], []).

init([]) ->
    process_flag(trap_exit, true),
    spawn_link(user, start_link,[]),
    {ok, []}.

handle_call(_E, _From, State) ->
        {noreply, State}.

handle_cast(_Message, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

handle_info(Message, State) ->
    {noreply, State}.

code_change(_OldVersion, State, _Extra) ->
    {ok, State}.

And user.erl (which is completely the same except init/1):

init([]) ->
     {ok, []}.

I thought that the servers would last forever. And if the first server dies another one gets {'EXIT', Pid, Reason} message.

But if you start the modules by serv:start_link() , the user module will exit immediately after the start with a message {'EXIT',Pid,normal} . Why does user die?

Was it helpful?

Solution 2

When you use the spawn link function, you are starting a new process which calls user:start_link. That process starts and links to a user gen_server process, and then exits, since the call to user:start_link returned. The user process is linked to that process, so it gets an exit signal. Since the user process isn't trapping exits, it also exits.

You should just run user:start_link in your serv:init function, as suggested in the comments.

OTHER TIPS

spawn and spawn_link are the two basic Erlang functions for starting a new process. Both will create a process which then calls the function with arguments as specified in the arguments to spawn/spawn_link. When that function ends the process automatically terminates with the exit reason normal. The difference between the functions is that spawn_link also creates a link between the two processes.

The gen_server:start_link function does much more than just creating the process by initiating the behaviour and then running a behaviour top-loop which provides all the behaviour functionality. Amongst other things the callback function init is called to initialise the behaviour and then return {ok,State} to tell the behaviour that everything has been initialised and went well and here is the local state it is to pass into all the callbacks. The callback functions of a gen_server are not meant to be called directly but by the behaviour.

So when you explicitly spawn a process just running the init function it will terminate as soon as the init function ends. This is what happening here.

The {'EXIT',Pid,Reason} messages comes from the processes being linked and that the process is trapping exits. When a process dies an exit signal is sent from the dying process to all the processes to which it is linked. When this signal arrives at a process trapping exits then it is converted to normal message and put in that processes message queue. This is what you are seeing here. Note that all this is done automatically because of the link and trapping exits.

I hope that helps. Sorry for being a bit over-didactic here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top