[Erlang]Странности с перекомпиляцией в beam и ловлей ошибок
От: Mr.Cat  
Дата: 17.07.08 22:35
Оценка:
Итак, эксперементирую с ловлей в linked-процессах.
Версия эрланга — afaik, 11b5 — из репозитория ubuntu 8.04.

Есть код:
1   -module(trap0).
2   -export([test/0]).
3
4   test() ->
5    process_flag(trap_exit, true),
6    link(spawn(fun()-> io:format("~p~n", [self()]), exit(because) end)),
7    receive
8        Msg -> io:format("~p~n", [Msg])
9    end.

Запускаю его в консоли:
cat@cat-kubuntu:~/erlang$ erl
Erlang (BEAM) emulator version 5.5.5 [source] [64-bit] [async-threads:0] [kernel-poll:false]

Eshell V5.5.5  (abort with ^G)
1> c(trap0).
{ok,trap0}
2> trap0:test().
<0.38.0>
{'EXIT',<0.38.0>,because}
ok


Далее заменяю строку 6 на
link(spawn(fun()-> io:format("~p~n", [self()]), throw(because) end))

Запускаю в консоли:
3> c(trap0).
{ok,trap0}
4> trap0:test().
{'EXIT',<0.40.0>,normal}
<0.45.0>
ok
=ERROR REPORT==== 18-Jul-2008::02:23:26 ===
Error in process <0.45.0> with exit value: {{nocatch,because},[{trap0,'-test/0-fun-0-',0}]}

Естественно, получаю репорт о неперехваченном исключении.

Далее заменяю строку 6 на:
link(spawn(fun()-> io:format("~p~n", [self()]), erlang:error(because) end)),

И запускаю в консоли:
5> c(trap0).
{ok,trap0}
6> trap0:test().
{'EXIT',<0.45.0>,{{nocatch,because},[{trap0,'-test/0-fun-0-',0}]}}
<0.52.0>
ok
=ERROR REPORT==== 18-Jul-2008::02:25:54 ===
Error in process <0.52.0> with exit value: {because,[{trap0,'-test/0-fun-0-',0}]}

Обратите внимание, процессу пришло сообщение с pid не текущего процесса, в котором бросалось исключение, а предыдущего.

Перезагружаю консоль. И выполняю тот же код.
7>
User switch command
 --> q
cat@cat-kubuntu:~/erlang$ erl
Erlang (BEAM) emulator version 5.5.5 [source] [64-bit] [async-threads:0] [kernel-poll:false]

Eshell V5.5.5  (abort with ^G)
1> c(trap0).
{ok,trap0}
2> trap0:test().
<0.38.0>

=ERROR REPORT==== 18-Jul-2008::02:30:12 ===
Error in process <0.38.0> with exit value: {because,[{trap0,'-test/0-fun-0-',0}]}

{'EXIT',<0.38.0>,{because,[{trap0,'-test/0-fun-0-',0}]}}
ok

Теперь все правильно.

В чем дело? Это я что-то делаю неправильно или это баг?
Re: [Erlang]Странности с перекомпиляцией в beam и ловлей оши
От: Mikl Kurkov Россия  
Дата: 18.07.08 08:35
Оценка: 6 (1)
Здравствуйте, Mr.Cat, Вы писали:

MC>Итак, эксперементирую с ловлей в linked-процессах.

MC>Версия эрланга — afaik, 11b5 — из репозитория ubuntu 8.04.

MC>Есть код:

MC>
MC>1   -module(trap0).
MC>2   -export([test/0]).
MC>3
MC>4   test() ->
MC>5    process_flag(trap_exit, true),
MC>6    link(spawn(fun()-> io:format("~p~n", [self()]), exit(because) end)),
MC>7    receive
MC>8        Msg -> io:format("~p~n", [Msg])
MC>9    end.
MC>

MC> ...
MC>В чем дело? Это я что-то делаю неправильно или это баг?
Тут проблема в том, что для экспериментов используется не вновь создаваемый процесс, а процесс оболочки Эрланга.
Функция test выполняется в пространстве этого процесса и завершается при получении любого сообщения,а не только
того которое нам нужно. Поэтому при повторном запуске мы получаем какое-то левое сообщение, а наше соощение зависает в очереди.
Проверить можно запустив flush() после нескольких вызовов. Получим что-то вроде:
Shell got {'EXIT',<0.75.0>,because}
Shell got {'EXIT',<0.77.0>,because}
Shell got {'EXIT',<0.79.0>,normal}
Shell got {'EXIT',<0.85.0>,because}
Shell got {'EXIT',<0.96.0>,normal}

это сообщения лежащие в очереди оболочки. Откуда берется лишнее сообщение тоже легко понять. Нужно выполнить flush после c(compile).
Похоже для компиляции создается отдельный процесс, который потом сообщает о своей смерти. Ну в общем это и не важно.
Главное, что следующий запуск trap0:test вернет как раз это сообщение, а свое положит в очередь.

Чтобы избежать этого проще всего обернуть вызов trap0:test в spawn, то есть создать свой новый процесс, а не использовать шелл.
Я уж не говорю о том, что менять режим работы оболочки (типа установки trap_exit) не вполне корректно.

--
Mikl
Re[2]: [Erlang]Странности с перекомпиляцией в beam и ловлей
От: Mikl Kurkov Россия  
Дата: 18.07.08 08:44
Оценка:
Ну и еще одно замечание — для линковки к новому процессу, лучше использовать spawn_link вместо link(spawn(...)).
В первом случае связь будет установлена до запуска процесса, сразу после создания.
А во втором такой гарантии нет и возможно завершение процесса до установки связи.

--
Mikl
Re[3]: [Erlang]Странности с перекомпиляцией в beam и ловлей
От: Mr.Cat  
Дата: 18.07.08 16:00
Оценка:
Спасибо. Похоже, дело было во flush() и процессе-компиляторе, как Вы и говорили. Сделав flush(), я обнаружил все недополученные сообщения.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.