Erlang -- gen_event

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表示事件管理器的名称或PidHandler可以是回调模块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/3gen_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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值