Системный актор — актор, который может обрабатывать ошибки, исходящие от акторов, с которыми установлен линк.
Все акторы в Эрланге делятся на два типа: обычные акторы и системные акторы. Если слинковать два обычных актора, то оба они рухнут, когда возникнет ошибка в одном из них. Системный же актор, если он слинкован с рухнувшим актором, просто получает сообщение об этом, но сам не рушится.
Все акторы спаунятся как нормальные. Чтобы актору стать системным, он должен выполнить биф process_flag(trap_exit, true). Это может сделать и посторонний актор: process_flag(Pid, trap_exit, true).
Системный актор, как легко догадаться, имеет важное значение: он не должен рушиться, он должен обрабатывать ошибки.
Чтобы посмотреть, как работает системный актор, создадим сначала просто два слинкованных актора.
-module(razdva).
-export([raz/0]).
raz() ->
spawn_link(fun() -> math:sqrt(-13) end),
loop().
loop() ->
receive
Mess -> io:format("Got: ~p~n",[Mess]), loop()
end.
Мы будем спаунить актор raz, а он в свою очередь заспаунит актор dva с помощью атомарной функции spawn_link/1, которая помимо спауна сразу устанавливает линк между двумя акторами: создающим и создаваемым. Второй актор должен моментально рухнуть, потому что пробует извлечь квадратный корень из -13.
1> spawn(razdva, raz, []).
<0.86.0>
=ERROR REPORT==== 25-Dec-2024::15:08:22.587817 ===
Error in process <0.87.0> with exit value:
{badarith,[{math,sqrt,[-13],[{error_info,#{module => erl_stdlib_errors}}]},
{razdva,'-raz/0-fun-0-',0,[{file,"razdva.erl"},{line,5}]}]}
2> is_process_alive(<0.86.0>).
false
Работает или нет актор raz, мы проверяем с помощью бифа is_process_alive/1. Как видно, он тоже рухнул вслед за своим слинкованным товарищем.
Теперь добавим всего одну строку — после функции вызова spawn_link/1.
process_flag(trap_exit, true),
Это должно сделать актор raz системным. Проверим:
1> spawn_link(razdva, raz, []).
<0.86.0>
Got: {'EXIT',<0.87.0>,
{badarith,[{math,sqrt,
[-13],
[{error_info,#{module => erl_stdlib_errors}}]},
{razdva,'-raz/0-fun-0-',0,
[{file,"razdva.erl"},{line,5}]}]}}
=ERROR REPORT==== 25-Dec-2024::15:12:14.294268 ===
Error in process <0.87.0> with exit value:
{badarith,[{math,sqrt,[-13],[{error_info,#{module => erl_stdlib_errors}}]},
{razdva,'-raz/0-fun-0-',0,[{file,"razdva.erl"},{line,5}]}]}
2> is_process_alive(<0.86.0>).
true
3> <0.86.0> ! hello.
Got: hello
hello
Ситуация изменилась. Во-первых, мы видим, что наш системный актор обработал сообщение об ошибке:
Got: {'EXIT',<0.87.0>,
В этом сообщении сначала идёт атом ‘EXIT’, потом пид рухнувшего актора, потом собственно ошибка. Во-вторых, наш системный актор продолжил работу. Об этом свидетельствует как результат вызова is_process_alive(<0.86.0>), так и то, что актор откликается на наши сообщения.
Copyright © 2025 Алексей Карманов