2014-12-08 3 views
1

Если у меня есть два модуля Erlang: A и B, отсоединены.Erlang scope of failure

В А:

start() -> register(A, spawn_link(A,init,[])). 

init() -> loop(). 

loop() -> 
    receive 
     {request, call_B} -> B:method(), 
     loop() 
    end. 

call_method() -> A ! {request, call_B}. 

В B:

start() -> register(B, spawn_link(B,init,[])). 

init() -> loop(). 

loop() -> 
    receive 
    {request, do} -> do_something..., 
    loop() 
    end. 

method() -> B ! {request, do}. 

Тогда в оболочке:

A:start(), 
B:start(), 
A:call_method(). 

Теперь, есть исключение в do_something и так Б умирает. Будет ли А в этом случае погибнуть?

Я попытался запустить A в оболочке, а затем убить A. И оболочка действительно перезапущена. Могу ли я сделать вывод, что ответ на этот вопрос - да, исходя из этого поведения?

+0

Вы имеете в виду, что у вас есть два процесса Erlang, а не два модуля? –

+0

Думаю, вы можете так сказать. Каждый модуль имеет start_link(). – xcoder

+0

@SteveVinoski Я отредактировал вопрос, чтобы сделать его более ясным. – xcoder

ответ

3

Я думаю, вы путаете процессы и модули, которые так распространены, я даже blogged about it. Пример моего блога показывает, что в одном модуле вы можете иметь код, который запускается в двух процессах. И обычно у вас есть.

Нет такой вещи, как «связанные модули». Только процессы могут быть связаны.

Так что в вашем примере.Таким образом, в вашем примере:

  • у вас есть процесс оболочки
  • вы икра процесс А, который использует цикл из модуля A и связан с оболочкой
  • вы икра процесса B, который использует цикл из модуля B и также связан с раскошеливаться
  • вы отправить сообщение для обработки A вызвать B:method

и теперь сложная часть: если method это примерно так:

method() -> 
    1/0. 

он все еще называется в процессе A и процесс A умирает. Он связан с оболочкой, поэтому оболочка оболочки и оболочка связаны с B, поэтому B умирает. (Я предполагаю, что вы не занимаетесь ловушкой).

Но обычно method что-то вроде этого:

method() -> 
    B ! do_something. 

И потом, это будет B, что сбои, которые будут carsh оболочки, что приведет к сбою A. Вы можете разорвать цепь, установив флаг trap_exit на одном из процессов. Например, в процессе оболочки. Попробуйте это в своей оболочке:

process_flag(trap_exit, true). % don't crash shell, when linked process dies 
spawn_link(fun() -> 1/0 end). % spawn_link process, that dies 
flush().      % shell did not die - it got message, that you can view with flush/0 
+0

Блестящее объяснение! Я думаю, вы правы, что меня путают с процессом и модулем ... Итак, делает ли последняя строка, что A выиграл? – xcoder

+0

Как писал zxq9. Связи двунаправлены, поэтому, если B умирает, тогда оболочка умирает и A также умирает. Это цепная реакция. Но если хотя бы один процесс - это улавливание выходов. Он получит сообщение вместо того, чтобы умереть, и оно сломает цепочку. – tkowal

+0

Спасибо против. Сегодня я чему-то научился. – xcoder

1

Ссылки в двух направлениях. Когда вы создаете связь между A и B и связью между A и C, все они находятся в одной и той же «области отказа». то же сообщение выхода не распространяется по всем ссылкам, но каждая ссылка является каналом распространения сообщения «EXIT». Если B сбой, он отправляет выход в A, поэтому он сбой, и когда он сбой, он отправляет выход на C. Этот вид цепочки может быть сколь угодно длинным или широким.

Процесс, который захватывает выходы, прерывает эту размножение и обрабатывает любое сообщение «EXIT», которое оно получает как просто сообщение, а не как указание, оно также должно быть аварийно завершено.

Вы можете создать какой-либо форме графа вы хотите со ссылками (понимание они двунаправленной, конечно - сделать циклический график вам нужно будет мониторы, которые являются одним из способов), но большую часть времени Программы Erlang разработаны на деревьях, где улов за выхождением происходит только возле корня дерева супервизорами.

Просто для удовольствия, вот иллюстрация, где авария распространяется через оболочку:

1> register(foo, spawn_link(fun() -> receive M -> io:format("~p~n", [M]) end end)). 
true 
2> register(bar, spawn_link(fun() -> receive M -> io:format("~p~n", [M]) end end)). 
true 
3> exit(whereis(bar), kill). 
** exception exit: killed 
4> foo ! hey. 
** exception error: bad argument 
    in operator !/2 
     called as foo ! hey 

Сначала мы икру два процесса, зарегистрированный как «Foo» и «бар», которые оба связаны с оболочкой , Все, что они делают, это сидеть и ждать, чтобы повторить какое-то сообщение. Прежде чем отправлять им какое-либо сообщение, мы жестоко убиваем «бар». 'сообщение о выходе bar отправляется в оболочку, поэтому оболочка умирает после строки 3 и перезапускается ее супервизором (поэтому мы получаем приглашение обратно в строке 4). Является ли «фу» еще живым? Мы пытаемся отправить ему сообщение, чтобы найти это ... он больше не существует! Когда оболочка разбилась, он отправил сообщение о выходе всем связанным процессам, а «foo» был одним из них (диспетчер оболочки - другой). «foo» не улавливал выходы, поэтому он умер, но супервизор оболочки был улавливающими выходами, поэтому получил сообщение {'EXIT', Proc, Reason} (супервизор оболочки знал, что это оболочка и что его нужно перезапустить, и сделал это).