Pull to refresh

Слежение за процессами и обработка ошибок, часть 3

Reading time3 min
Views5.5K

Преамбула


В предыдущих частях (часть 1, часть 2) мы полностью рассмотрели механизм создания двунаправленных связей между процессами и процесс распространения ошибок. В данной статье будет разобран, достаточно простой, механизм мониторов и ещё несколько аспектов касающихся работы с процессами.

Мониторы


Функции для работы с мониторами

Небольшой перечень функций, которые могут понадобиться для работы с мониторами:
  • erlang:monitor/2 — вызывающий функцию процесс начинает мониторинг указанного процесса;
  • erlang:demonitor/1/2 — отключение функции мониторинга;
  • erlang:spawn_monitor/1/3 — создание нового процесса и привязка вызывающего функцию процесса в качестве монитора.

Если наблюдаемый процесс падает, то монитор получает сообщение {'DOWN', Reference, process, Pid, Reason}, где
  1. 'DOWN' — означает что процесс упал;
  2. Reference — ссылка на монитор;
  3. process — объектом мониторинга является процесс (в документации написано, что в текущей версии эрланга, мониторить можно только процессы, возможно, в будущем прикрутят что-то ещё);
  4. Pid — Pid упавшего процесса;
  5. Reason — причина.


Одно из отличий создания связи и монитора заключается в том, что если вы попытаетесь создать связь с несуществующим процессом, вызывающий процесс упадет, а в случае монитора вы сразу получите сообщение {'DOWN', Reference, process, Pid, Reason}. Давайте попробуем это на практике — запускаем eshall и выполняем следующие команды.

(emacs@aleksio-mobile)1> self().
<0.36.0>
(emacs@aleksio-mobile)2> erlang:link(c:pid(0,777,0)).
** exception error: no such process or port
     in function  link/1
        called as link(<0.777.0>)
(emacs@aleksio-mobile)3> self().
<0.39.0>
(emacs@aleksio-mobile)4> flush().
ok
(emacs@aleksio-mobile)5> erlang:monitor(process, c:pid(0,777,0)).
#Ref<0.0.0.43>
(emacs@aleksio-mobile)6> self().
<0.39.0>
(emacs@aleksio-mobile)7> flush().
Shell got {'DOWN',#Ref<0.0.0.43>,process,<0.777.0>,noproc}
ok
(emacs@aleksio-mobile)8> 


В первой строке мы узнаем Pid оболочки, затем пытаемся связать текущий процесс с заведомо не существующим erlang:link(c:pid(0,777,0)), после чего оболочка падает, в очереди сообщений пусто. Пятой командой вызываем функцию erlang:monitor(process, c:pid(0,777,0)), которая создает и возвращает ссылку на монитор. Так как процесса с Pid = <0.777.0> не существует в очередь оболочки приходит сообщение {'DOWN',#Ref<0.0.0.43>,process,<0.777.0>,noproc}, которое говорит нам, что процесса <0.777.0> в системе нет.

Напишем небольшой модуль, для закрепления знаний о мониторах.
-module(testm).
-export([start_m/0, stop_m/1, loop/1]).

start_m() ->
	erlang:spawn_monitor(?MODULE, loop, [self()]).	

stop_m(Ref) ->	
	erlang:demonitor(Ref).

loop(Shell) ->
	receive
		kill -> exit(kill);
		reason -> exit("Another reason");
		Msg -> Shell ! {get_msg, Msg}
	end.


Функция spawn_monitor создает процесс с телом loop и делает вызывающий процесс (в нашем примере shell) монитором.

(emacs@aleksio-mobile)2> {Pid, Ref} = testm:start_m().
{<0.43.0>,#Ref<0.0.0.62>}
###Процесс создан <0.43.0>, ссылка на монитор #Ref<0.0.0.62>

(emacs@aleksio-mobile)3> Pid ! hello.
hello
###Отправляем процессу сообщение

(emacs@aleksio-mobile)4> flush().
Shell got {get_msg,hello}
Shell got {'DOWN',#Ref<0.0.0.62>,process,<0.43.0>,normal}
ok
###В ответ процесс нам отправляет сообщение {get_msg,hello}
###И завершает свою работу с причиной normal

(emacs@aleksio-mobile)5> f(Pid), f(Ref).
ok
###Делаем переменные Pid и Ref свободными
###Дальше все по аналогии

(emacs@aleksio-mobile)6> {Pid, Ref} = testm:start_m().
{<0.48.0>,#Ref<0.0.0.77>}
(emacs@aleksio-mobile)7> Pid ! kill.
kill

(emacs@aleksio-mobile)8> flush().
Shell got {'DOWN',#Ref<0.0.0.77>,process,<0.48.0>,kill}
ok

(emacs@aleksio-mobile)9> f(Pid), f(Ref).
ok

(emacs@aleksio-mobile)10> {Pid, Ref} = testm:start_m().
{<0.53.0>,#Ref<0.0.0.91>}
(emacs@aleksio-mobile)11> Pid ! reason.
reason

(emacs@aleksio-mobile)12> flush().
Shell got {'DOWN',#Ref<0.0.0.91>,process,<0.53.0>,"Another reason"}
ok

(emacs@aleksio-mobile)13> testm:stop_m(Ref).
true

(emacs@aleksio-mobile)14> 


Вопрос к читателям: как вы заметили при каждом новом создании процесса ссылка на монитор тоже новая, но отключение монитора мы сделали только в конце. Останутся ли предыдущие ссылки где-либо в состоянии нашего процесс и может ли это как-нибудь повлиять на работу?

Заключение


Мы рассмотрели мониторы — достаточно удобный и простой механизм слежения за состоянием других процессов. Надеюсь, каждый сможет применить их в своих задачах, реализованных на языке эрланг.

Что почитать?


1. Отличная интерактивная документация.
2. ERLANG Programming by Francesco Cesarini and Simon Thompson.
3. Статья на RSDN: обработка ошибок в Erlang.
Tags:
Hubs:
+19
Comments5

Articles

Change theme settings