Erlang World


top > otp > gen_event 1

gen_event

gen_eventとは

OTPにはイベントマネージャ(event manager)という概念があります。 このイベントマネージャに対して、イベント(event)を送信することにより、決められた動作を行なうことができます。
例えば、エラーのログを取るイベントマネージャに対して、エラーが起きたことをイベントで伝えるといった ような使い方をします。

イベントマネージャがどのように動作を行なうかということはユーザが定義しなければなりません。 このイベントに対する取り扱い方式を決める物がイベントハンドラというものです。上の例では、 エラーのログを取るという動作がイベントハンドラとして定義されています。

Erlangでこのイベント管理を担当しているのが、OTPの gen_event です。

以下に使用するサンプルを掲示します。

-module(terminal_logger).
-export([init/1, handle_event/2, terminate/2]).

init(_Args) ->
    {ok, []}.

handle_event(ErrorMsg, State) ->
    io:format("***Error*** ~p~n",[ErrorMsg]),
    {ok, State}.

terminate(_Args, _State) ->
    ok.
1> gen_event:start_link({local, error_man}).
{ok,<0.33.0>}
2> gen_event:add_handler(error_man, terminal_logger,[]).
ok
3> gen_event:notify(error_man, no_reply).
***Error*** no_reply
ok
4> gen_event:stop(error_man).
ok

イベントマネージャの起動

例を見てもらってわかる通り、gen_eventは比較的簡単です。ここではgen_eventのイベントマネージャの 起動方法から学びます。

イベントマネージャを起動するには、以下の関数を使います。

start_link() -> Result start_link(EventMgrName) -> Result
EventMgrName = {local,Name} | {global,Name}
Name = atom()
Result = {ok,Pid} | {error,{already_started,Pid}}
Pid = pid()
イベントマネージャの開始にはにはコールバックは存在しません。
1> gen_event:start_link({local, error_man}).
{ok,<0.33.0>}

イベントハンドラの追加

イベントマネージャの動作を定義するために、イベントハンドラを与えます。

イベントハンドラの追加には以下の関数を使います。

add_handler(EventMgrRef, Handler, Args)
EventMgr = Name | {Name,Node} | {global,Name} | pid()
Name = Node = atom()
Handler = Module | {Module,Id}
Module = atom()
Id = term()
Args = term()
Result = ok | {'EXIT',Reason} | term()
Reason = term()
EventMgrRefはイベントマネージャです。Handlerはコールバックの実装モジュールです。 以後、このHandlerがイベントハンドラの名前となります。 Argsにより、イベントハンドラの初期状態を与えます。

パラメータHandlerにより指定されたモジュールには、次のコールバック関数が必要となります。

Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate}
InitArgs = Args | {Args,Term}
Args = Term = term()
State = term()
gen_event:add_handler/3 のパラメータArgsが、InitArgsとして渡されます。 返り値は決められた形にしなければなりません。

以下の部分でイベントハンドラを追加しています。

2> gen_event:add_handler(error_man, terminal_logger,[]).
ok

コールバックは次の部分です。

-module(terminal_logger).
.....

init(_Args) ->
    {ok, []}.

.....

gen_event:add_handlerで指定された値と、同じ名前のモジュールの中にあるコールバックが実行されます。

イベントの通知

それでは、イベントマネージャに対してイベントを通知してみましょう。イベントの通知には以下の 関数を使います。

notify(EventMgrRef, Event) -> ok
EventMgrRef = Name | {Name,Node} | {global,Name} | pid()
Name = Node = atom()
Event = term()
EventMgrRefはイベントマネージャです。Eventはイベントマネージャに渡すパラメータです。

gen_event:notify/2 のコールバック関数は次のような書式になっています。なお、コールバック関数が含まれるモジュールは gen_event:add_handler/3 で指定されたモジュールです。

Module:handle_event(Event, State) -> Result
Event = term()
State = term()
Result = {ok,NewState} | {ok,NewState,hibernate}
Stateはgen_eventのhandlerの状態です。Eventは gen_event:notify/2 のEventで与えられた パラメータとなっています。
3> gen_event:notify(error_man, no_reply).
***Error*** no_reply
ok
handle_event(ErrorMsg, State) ->
    io:format("***Error*** ~p~n",[ErrorMsg]),
    {ok, State}.

イベントハンドラの停止

gen_event:add_handler/3 で設定したハンドラを終了するには、次の関数を使います。

delete_handler(EventMgrRef, Handler, Args) -> Result
EventMgrRef = Name | {Name,Node} | {global,Name} | pid()
Name = Node = atom()
Handler = Module | {Module,Id}
Module = atom()
Id = term()
Args = term()
Result = term() | {error,module_not_found} | {'EXIT',Reason}
Reason = term()
EventMgrRefがイベントマネージャで、 Handlerが停止したいイベントハンドラのコールバックモジュール名です。

この関数は、次のコールバックを必要としています。

Module:terminate(Arg, State) -> term()
Arg = Args | {stop,Reason} | stop | remove_handler
| {error,{'EXIT',Reason}} | {error,Term}
Args = Reason = Term = term()
Moduleは Handler の名前のモジュールです。

イベントマネージャの停止

最後にイベントマネージャの停止をします。これには次の関数を使います。

stop(EventMgrRef) -> ok
EventMgrRef = Name | {Name,Node} | {global,Name} | pid()
Name = Node = atom()
イベントマネージャを終了する前に、 全てのイベントハンドラに対して、Module:terminate(stop,...)を呼び出します。
4> gen_event:stop(error_man).
ok

実際にはgen_eventはもっと多彩なことが出来ます。詳しい内容については次の節で扱います。


Yuichi ITO. All rights reserved.
mail to : ad
inserted by FC2 system