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