Erlang. Правильный способ остановить процесс

Добрый день, у меня есть следующая настройка для моего небольшого обслуживания:

-module(mrtask_net).

-export([start/0, stop/0, listen/1]).

-define(SERVER, mrtask_net).

start() ->
    Pid = spawn_link(fun() -> ?MODULE:listen(4488) end),
    register(?SERVER, Pid),
    Pid.

stop() ->
    exit(?SERVER, ok).

....

И вот фрагмент repl:

([email protected])83> mrtask_net:start().
<0.445.0>
([email protected])84> mrtask_net:stop().
** exception error: bad argument
     in function  exit/2
        called as exit(mrtask_net,ok)
     in call from mrtask_net:stop/0
([email protected])85> 

Как вы видите, процесс остановки создает ошибку, однако процесс останавливается. Что означает эта ошибка и как сделать чистую вещь?

Ответ 1

Не будучи программистом Erlang и только из документации exit (здесь), я бы сказал, что exit требует идентификатора процесса как первого в то время как вы передаете ему атом (?SERVER).

Try

exit(whereis(?SERVER), ok).

вместо этого (whereisвозвращает идентификатор процесса, связанный с именем, см. здесь)

Ответ 2

Вам нужно изменить вызов на exit/2, как указал @MartinStettner. Причина, по которой процесс все равно прекращается, заключается в том, что вы запустили его с помощью spawn_link. Затем ваш процесс связан с процессом оболочки. Когда вы вызывали mrtask_net:stop(), ошибка приводила к сбою процесса оболочки, который затем приводил к сбою вашего процесса при их соединении. Затем автоматически запускается новый процесс оболочки, поэтому вы можете продолжать работать с оболочкой. Обычно вы хотите запускать свои серверы с помощью spawn_link, но это может вызвать путаницу, когда вы тестируете их из оболочки, и они просто "бывают", чтобы умереть.

Ответ 3

Я предлагаю вам придерживаться OTP. Это действительно дает вам массу преимуществ (я вряд ли могу вообразить тот случай, когда OTP не приносит пользы).

Итак, если вы хотите остановить процесс в OTP, вы должны сделать что-то вроде этого для gen_server:

% process1.erl
% In case you get cast message {stopme, Message}
handle_cast({stopme, Message}, State) ->
    % you will stop
    {stop, normal, State}
handle_cast(Msg, State) ->
    % do your stuff here with msg
    {noreply, State}.

% process2.erl
% Here the code to stop process1
gen_server:cast(Pid, {stopme, "It time to stop!"}),

Подробнее об этом вы можете найти здесь: http://www.erlang.org/doc/man/gen_server.html