Erlang: Почему я не могу связать два gen_servers?

У меня есть два модуля gen_server.
Первый 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}.

И user.erl (полностью то же самое, за исключением init/1):

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

Я думал, что серверы будут жить вечно. И если первый сервер умирает, другой получает сообщение {'EXIT', Pid, ​​Reason}.

Но если вы запустите модули с помощью serv:start_link() , модуль user выйдет сразу после запуска с сообщением {'EXIT',Pid,normal . Почему умирает пользователь?


person user2461860    schedule 25.07.2013    source источник
comment
вместо этого spawn_link(user, start_link,[]) попробуйте user:start_link().   -  person Khashayar    schedule 25.07.2013
comment
Примечание: никогда не называйте свой модуль user. Erlang уже поставляется с модулем с таким именем, и вы либо не увидите свой собственный модуль, либо запретите загрузку EVM, потому что ожидаемый модуль user ведет себя не так, как ожидалось.   -  person ZeissS    schedule 26.07.2013


Ответы (2)


Когда вы используете функцию связи порождения, вы запускаете новый процесс, который вызывает user:start_link. Этот процесс запускается и связывается с пользовательским процессом gen_server, а затем завершается, поскольку был возвращен вызов user:start_link. Пользовательский процесс связан с этим процессом, поэтому он получает сигнал выхода. Поскольку пользовательский процесс не перехватывает выходы, он также завершается.

Вы должны просто запустить user:start_link в своей функции serv:init, как это предлагается в комментариях.

person kjw0188    schedule 25.07.2013

spawn и spawn_link — это две основные функции Erlang для запуска нового процесса. Оба создадут процесс, который затем вызовет функцию с аргументами, указанными в аргументах spawn/spawn_link. Когда эта функция завершается, процесс автоматически завершается с причиной выхода normal. Разница между функциями заключается в том, что spawn_link также создает связь между двумя процессами.

Функция gen_server:start_link делает гораздо больше, чем просто создает процесс, инициируя поведение, а затем запуская верхний цикл поведения, который обеспечивает все функциональные возможности поведения. Среди прочего функция обратного вызова init вызывается для инициализации поведения, а затем возвращает {ok,State}, чтобы сообщить поведению, что все было инициализировано и прошло хорошо, и вот локальное состояние, которое должно передаваться во все обратные вызовы. Функции обратного вызова gen_server предназначены не для прямого вызова, а для поведения.

Поэтому, когда вы явно запускаете процесс, просто выполняющий функцию init, он завершится, как только завершится функция init. Это то, что происходит здесь.

Сообщения {'EXIT',Pid,Reason} исходят от связанных процессов и о том, что процесс перехватывает выходы. Когда процесс умирает, умирающий процесс отправляет сигнал выхода всем процессам, с которыми он связан. Когда этот сигнал поступает на выходы перехвата процесса, он преобразуется в обычное сообщение и помещается в очередь сообщений этого процесса. Это то, что вы видите здесь. Обратите внимание, что все это делается автоматически из-за ссылки и перехвата выходов.

Надеюсь, это поможет. Извините, что был немного чрезмерно дидактичен здесь.

person rvirding    schedule 25.07.2013