`
litaocheng
  • 浏览: 333458 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

gen_event 讲解

阅读更多
OTP中,事件管理器(event manager)用来接收事件,这里的事件非常广泛,可以为错误,警告各种各样erlang允许的信息。
事件管理器拥有零个或多个事件处理器(event handler)。当事件管理器收到一个事件时,此事件会被管理器内部安装的所有处理器处理。
其实在事件管理器(gen_event behaviour)中,拥有一个[{Module, State}],其保存安装的处理器(Module模块)及对应的状态。当收到事件时,管理器遍历调用Module的
Module:handle_event/2函数进行处理。

callbacks接口
1. init(InitArg)
处理器安装后,进行初始化,返回Module对应的状态
2. handle_event(Event, State)
处理各种event
3. handle_call(Request, State)
处理同步调用
4. terminate(Arg, State)
处理器被删除或事件管理器停止时,Module调用terminate
完成详细规范请参考erlang man手册

example-日志记录模块,保存最近的5条错误日志

-module(recent_logger).
-behaviour(gen_enevt).

-export([start/0, stop/0, log/1, report/0, release/0])

%% gen_event callbacks
-export([init/1, handle_event/2, handle_call/2, terminate/2]).
-define(NAME, logger_manager).

%% start behaviour
start() ->
	case gen_event:start_link({local, ?NAME}) of
		Ret = {ok, _Pid} ->
			gen_event:add_handler(?NAME, ?MODULE, []),
			Ret;
		Other ->
			Other
	end.

%% stop
stop() ->
	gen_envent:stop(?NAME).

%% notify an envent about log
log(E) ->
	gen_enevt:notify(?NAME, {log, E}).

%% report the all log
report() ->
  gen_event:call(?NAME, ?MODULE, report).

%% release this handler
release() ->
  gen_event:delete_handler(?NAME, ?MODULE, release).

init(_Arg) ->
	io:format("start recent log handler~n"),
	{ok, []}.

handle_event({log, E}, List) ->
	{ok, trim([E | List])}.

handle_call(report, List) ->
  List.

terminate(stop, _List) ->
	io:format("recent log handler stop~n"),
	ok;
terminate(release, _List) ->
	io:format("recent log handler release~n"),
	ok.

%% save the recent five log
trim([E1, E2, E3, E4, E5 | []) ->
	[E1, E2, E3, E4, E5];
trim(List) ->
	List.



gen_event使用
1. 启动gen_event
gen_event:start_link({local, ?NAME})用来启动命名为?NAME所表示宏的事件管理器。
同gen_server一样,命名可以为{global, ?NAME}或者没有命名使用Pid交互。此模块作为supervision tree的worker时,必须使用start_link启动,
而单独应用可以使用start

2. 添加一个handler
gen_event:add_handler(?NAME, ?MODULE, [])将本Module作为一个handler添加到事件管理器中,函数内部会调用Module:init/1函数,其中参数为
add_handler/3的第三个参数。

3. 通知一个事件
当我们想要事件管理器记录一个日志时,我们通过gen_enevt:notify(?NAME, {log, E}).向事件管理器发送一个事件,这样事件管理就会依次调用其内部
安装的所有处理器处理此事件,并更新对应处理器的状态。具体的处理过程在Module的handle_event/2中进行。此处是{ok, trim([E | List])}保存日志消息。

4. 删除一个事件
gen_event:delete_handler(?NAME, ?MODULE, [])我们将?MODULE指定的处理器删除,其中会调用Module:terminate/2进行清除。

5. 同步调用
gen_server:call(?NAME, ?MODULE, report)用来进行同步调用,需要注意的是:此函数不同于gen_enevt:notify/2,其拥有三个参数,第二个参数用来指明调用那个事件处理器进行处理此请求,而notify是通知所有的事件处理器某个事件,因此这里是不同的。
函数调用Module:handle_call/2返回结果,这里直接返回保存的log List

6. 停止事件管理器
如果事件管理器应用在supervision tree中,不需要提供stop函数,监督树会自动清除事件管理器。如果是单独的应用,需要调用 gen_envent:stop(?NAME)停止事件管理器。
此处与gen_server相似,具体参考supervision shutdown strategy

通过上面的描述,您对gen_enevt熟悉了么?把example代码自己书写一遍,理解会更深刻!
分享到:
评论
1 楼 cheng02 2012-08-30  
5、的第一句打错了,gen_server:call应该是gen_event:call

相关推荐

Global site tag (gtag.js) - Google Analytics