モニターはリンクと違って、終了シグナルは双方に届けられるものではありません。 つまり終了シグナルが片側通行なのです。
モニターにおいては、
erlang:monitor(process,Pid)
を実行した側のみが終了プロセスを受け取ります。
システムプロセスと同様に、 モニター(関数を実行した側)は終了シグナルを受け取ってもメッセージとして処理されるだけです。
サンプルプログラムを通して確認してみます。
-module(mymonitor).
-export([start_monitor/0, start_server/0]).
start_server() ->
spawn(fun() -> server_loop() end).
server_loop() ->
receive
{add, X, Y} ->
io:format("add: ~p~n",[X + Y]),
server_loop()
end.
start_monitor() ->
spawn(fun() -> monitor_loop() end).
monitor_loop() ->
receive
{monitor,Pid} ->
erlang:monitor(process, Pid),
monitor_loop();
{exit,Why} ->
erlang:exit(Why);
Other ->
io:format("In moniter:~p~n",[Other]),
monitor_loop()
end.
前回までのプログラムと少し似ていますが、今回のプログラムは仲介サーバがありません。 代わりに、プロセスを監視するためのモニターサーバを利用しています。
モニターサーバには、モニターさせる、落とす、終了メッセージを受け取るという仕事があります。
それでは、実行してみましょう。
処理サーバを2つと、モニターサーバを作成します。
1> Pid = mymonitor:start_server().
<0.33.0>
2> Pid2 = mymonitor:start_server().
<0.35.0>
3> Monitor = mymonitor:start_monitor().
<0.37.0>
モニターに登録します
4> Monitor ! {monitor,Pid}.
{monitor,<0.33.0>}
5> Monitor ! {monitor,Pid2}.
{monitor,<0.35.0>}
処理サーバの一つをわざと落とす。
6> Pid ! {add,dog,cat}.
{add,dog,cat}
=ERROR REPORT==== 15-May-2008::23:53:04 ===
Error in process <0.33.0> with exit value: {badarith,[{mymonitor,server_loop,0}]}
In moniter:{'DOWN',#Ref<0.0.0.42>,process,<0.33.0>,
{badarith,[{mymonitor,server_loop,0}]}}
モニターは生きています。
7> is_process_alive(Monitor).
true
モニターを殺します。
8> Monitor ! {exit,killed}.
{exit,killed}
落としていない処理サーバは生きています。
9> is_process_alive(Pid2).
true
プロセスシステムで処理サーバとリンクしていたら、Pid2も死んでいました。 しかし、モニターはリンクとは違って終了シグナルは一方通行なのでPid2は生きています。
関数(BIF erlang) | 役割 |
---|---|
erlang:monitor(Type, Item) | Typeは現在のところ、'process'のみ可能です。将来拡張される予定です。 ItemはプロセスIDです。Pidとして直接設定することも可能ですが、{RegName, Node} や RegName でも可能です。 RegNameは登録済みプロセスのアトムで、Nodeはノードです。 この関数の返り値はリファレンスです。 もしItemがダウンしたとき、この関数を実行したプロセスには'Down'メッセージが届きます。 書式は {'DOWN', MonitorRef, Type, Object, Info} です。 Object はPidで作成した場合はPid、 それ以外は {RegName,Node} となります。 Info はexitした理由です。 process_flag(trap_exit,true) が呼び出されていない状態で、Pidが死んでいれば例外を投げます。 |
erlang:demonitor(MonitorRef) | モニターを解除します。 |
monitor_node(Node, Flag) | ノードをモニターします。 Flagはboolean型でtrueならモニターをon、falseならモニターをoffします。 |