gen_event
gen_event
行为模块提供了事件处理功能,由一个通用的事件管理器进程和多个动态添加的事件处理程序构成。
事件管理器具有一组标准的接口函数,包括跟踪和错误报告功能。
每个事件处理程序都被实现为一个回调模块,导出一组预定义的函数。
行为函数与回调函数之间的关系如下:
gen_event module Callback module
---------------- ---------------
gen_event:start
gen_event:start_link -----> -
gen_event:add_handler
gen_event:add_sup_handler -----> Module:init/1
gen_event:notify
gen_event:sync_notify -----> Module:handle_event/2
gen_event:call -----> Module:handle_call/2
- -----> Module:handle_info/2
gen_event:delete_handler -----> Module:terminate/2
gen_event:swap_handler
gen_event:swap_sup_handler -----> Module1:terminate/2
Module2:init/1
gen_event:which_handlers -----> -
gen_event:stop -----> Module:terminate/2
- -----> Module:code_change/3
事件管理器会有多个回调模块,当这些回调模块返回失败Reason
或者返回错误值Term
时,事件管理器不会失败。
通过调用Module:terminate/2
(参数为{error,{'EXIT',Reason}}
或{error,Term}
)删除相应的事件处理程序,并不会影响其他事件处理器。
可以通过gen_event:start()
或gen_event:start(EventMgrName | Options)
或gen_event:start(EventMgrName, Options)
或gen_event:start_link()
或gen_event:start_link(EventMgrName | Options)
或gen_event:start_link(EventMgrName, Options)
创建一个事件管理器。
注意,事件管理器会自动捕获退出信号。
可通过stop(EventMgrRef)
或stop(EventMgrRef, Reason, Timeout)
来终止一个事件管理器,在事件管理器终止前,会调用Module:terminate(stop, ....)
终止每个事件处理程序。
启动了事件管理器后,就可以通过调用gen_event:add_handler(EventMgrRef, Handler, Args)
动态添加一个事件处理器,其中EventMgrRef
表示事件管理器的名称或Pid
,Handler
可以是回调模块Module
也可以是{Module,Id}
,其中,当多个事件处理器都用同一个回调模块时,Id
用于区分不同的事件处理器。Args
将会作为Module:init(Args)
的参数用于初始化事件处理器。
添加后可通过调用gen_event:delete_handler(EventMgrRef, Handler, Args)
删除事件处理器。
添加事件处理器后可通过gen_event:notify(EventMgrRef, Event)
或gen_event:sync_notify(EventMgrRef, Event)
分别异步、同步触发事件,此时事件管理器会调用所有事件处理器的回调函数Module:handle_event(Event, State)
来处理事件Event
。
可以通过gen_event:call(EventMgrRef, Handler, Request)
或gen_event:call(EventMgrRef, Handler, Request, Timeout)
通过事件管理器去调用相应的事件处理器的回调函数Module::handle_call(Request, State)
。
另外,可通过gen_event:swap_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2})
来替换事件处理器,流程为,首先调用Module1:terminate(Args1,...)
去终止处理器1,获得返回值term
,再调用Module2:init({Args2,Term})
去初始化处理器2。
gen_event:add_sup_handler/3
与gen_event:add_handler/3
是一样的,只是gen_event:add_sup_handler/3
会调用方和处理器之间建立,以保证任意一方终止时,对方能够做相应的处理。
gen_event:swap_sup_handler/3
同上。
例子
以下是两个回调模块:
-module(terminal_logger).
-behaviour(gen_event).
-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.
-module(file_logger).
-behaviour(gen_event).
-export([init/1, handle_event/2, terminate/2]).
init(File) ->
{ok, Fd} = file:open(File, [read,write]),
{ok, Fd}.
handle_event(ErrorMsg, Fd) ->
io:format(Fd, "***Error*** ~p~n", [ErrorMsg]),
{ok, Fd}.
terminate(_Args, Fd) ->
file:close(Fd).
我们可以通过
1> gen_event:start({local, error_man}).
{ok,<0.31.0>}
启动一个名为error_man
的事件管理器,通过
2> gen_event:add_handler(error_man, terminal_logger, []).
ok
将处理器terminal_logger
添加到事件管理器中。当我们调用gen_event:notify(error_man, no_reply).
触发事件时,terminal_logger
会做相应的处理,如下:
3> gen_event:notify(error_man, no_reply).
***Error*** no_reply
ok
添加事件处理器file_logger
,然后再触发noreply
事件:
4> gen_event:add_handler(error_man, file_logger, ["file_logger.txt"]).
ok
5> gen_event:notify(error_man, no_reply).
ok
***Error*** no_reply
打开文件file_logger.txt
会发现里面写入了内容:***Error*** no_reply
。
删除file_logger
,然后再触发noreply
事件:
6> gen_event:delete_handler(error_man, file_logger, stop).
ok
7> gen_event:notify(error_man, no_reply111).
ok
***Error*** no_reply111
此时会发现文件file_logger.txt
会发现里面不会再写入***Error*** no_reply111
。