Итак, эксперементирую с ловлей в 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
Теперь все правильно.
В чем дело? Это я что-то делаю неправильно или это баг?
Здравствуйте, 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
Ну и еще одно замечание — для линковки к новому процессу, лучше использовать spawn_link вместо link(spawn(...)).
В первом случае связь будет установлена до запуска процесса, сразу после создания.
А во втором такой гарантии нет и возможно завершение процесса до установки связи.
--
Mikl
Спасибо. Похоже, дело было во flush() и процессе-компиляторе, как Вы и говорили. Сделав flush(), я обнаружил все недополученные сообщения.