Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5011884
  • 博文数量: 921
  • 博客积分: 16037
  • 博客等级: 上将
  • 技术积分: 8469
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-05 02:08
文章分类

全部博文(921)

文章存档

2020年(1)

2019年(3)

2018年(3)

2017年(6)

2016年(47)

2015年(72)

2014年(25)

2013年(72)

2012年(125)

2011年(182)

2010年(42)

2009年(14)

2008年(85)

2007年(89)

2006年(155)

分类: Erlang

2013-11-02 20:25:28

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条错误日志 


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

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

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

  7. %% start behaviour
  8. start() ->
  9.     case gen_event:start_link({local, ?NAME}) of
  10.         Ret = {ok, _Pid} ->
  11.             gen_event:add_handler(?NAME, ?MODULE, []),
  12.             Ret;
  13.         Other ->
  14.             Other
  15.     end.

  16. %% stop
  17. stop() ->
  18.     gen_envent:stop(?NAME).

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

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

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

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

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

  33. handle_call(report, List) ->
  34.   List.

  35. terminate(stop, _List) ->
  36.     io:format("recent log handler stop~n"),
  37.     ok;
  38. terminate(release, _List) ->
  39.     io:format("recent log handler release~n"),
  40.     ok.

  41. %% save the recent five log
  42. trim([E1, E2, E3, E4, E5 | []) ->
  43.     [E1, E2, E3, E4, E5];
  44. trim(List) ->
  45.     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代码自己书写一遍,理解会更深刻!

文章来自:http://erlangdisplay.iteye.com/blog/315391





阅读(1342) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~