转自:http://www.myexception.cn/program/1569725.html

Erlang OTP gen_event (0)
原英文文档:http://www.erlang.org/erldoc?q=&x=0&y=0
Tips:看到网页右边的搜索功能了么,保存这个实用网页吧。

一个实现事件处理功能行为模块,可以动态的删除和增加任意数量事件的事件管理器(event_manager),事件管理器使用这个模块将实现一套标准的接口功能,包括跟踪和错误报告功能。同样他也适合OTP 监控树(supervision tree)

每个事件处理程序被实现为一个回调模块导出一组预定义的功能:
   
每一个事件处理程序都是一个回调模块,一个事件管理器必可以动态的增加和删除事件回调,所以gen_event
会比其它behaviours(gen_server,gen_fsm)容错更新好,如果安装好的事件处理回调失败(fails with Reason
or returns a bad value
Term),这个事件管理器是不会失败的,他会删除这个事件回调,并调用对应事件的terminate/2.如果给的参数如:{error,
{'EXIT',Reasion}} or {error,Term},其它事件是不会受到影响的。
   事件管理不会自动处理(trap)exit signals,%%手动调用 process_flag(trap_exit, true).

如果事件管理器回调返回值里面hibernation有可以进入休眠状态(hibernation),这对于长期处于空闲状态的server来说非常好,
不过此特性会使用2个垃圾回收器(when hibernating and shortly after waking
up),不适合处理非常多的事件管理器。只要其中一个事件处理返回hibernate就会使event manager进入休眠状态。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

start_link() -> Result
start_link(EventMgrName) -> Result
Types:EventMgrName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
Name = atom()
GlobalName = ViaName = term()
Result = {ok,Pid} | {error,{already_started,Pid}}
Pid = pid()

创建一个事件管理器进程(event_manager)这个函数会被supervisor调用创建,保证event_manager与supervisor相连接(link),
  如果EventMrName={local,Name},event manager 会像用register/2注册一样本地注册。
  如果EventMrName={global,GlobalName},event manager 会像用global:register_name/2注册一样本地注册。
  如果不提供Name就不会注册。
 
如果EventMrName = {via,Module,ViaName} event
manager会使用Module里面自己定义的register_name/2,unregister_name/1,whereis_name/1
and send/2,这些函数的功能和global里面功能一致,否则{via,Module,ViaName}无用

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

start() -> Result
start(EventMgrName) -> Result Types:
EventMgrName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
Name = atom()
GlobalName = ViaName = term()
Result = {ok,Pid} | {error,{already_started,Pid}}
Pid = pid()

创建一个独立的event manager 进程,例如没有监控树,其它参见start_link/0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
a

add_handler(EventMgrRef, Handler, Args) -> Result

Types:
EventMgr = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()
Handler = Module | {Module,Id}
Module = atom()
Id = term()
Args = term()
Result = ok | {'EXIT',Reason} | term()
Reason = term()

给event manager 增加一个新的事件回调(event handler),会调用Module:init/1来初始化他的状态
    EventMgr 参数可以:pid(),Name,{Name,Node}(如果这个事件管理注册在其它节点上){global,GlobalName}{via,Module,ViaName}
Args 参数是传给Module:init/1使用的
如果Module:init/1返回一个正确的值,event manager会增加event handler,此函数也会返回ok.
如果Module:init/1带Reason的失败或返回{error,Reasion} 这具event hander会被忽略,此函数会返回{'EXIT',Reason}或{error,Reason}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

add_sup_handler(EventMgrRef, Handler, Args) -> Result

Types:
EventMgr = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()
Handler = Module | {Module,Id}
Module = atom()
Id = term()
Args = term()
Result = ok | {'EXIT',Reason} | term()
Reason = term()

和add_handler/3一样添加一个event handler,但会在event handler 和被调用的进程之间添加监控连接(supervise ther connection),
如果这个进程terminateswith Reason event manager 会用Module:terminate/2 {stop,Reason} 把这个event handler 删除
如果event handler 被删除,event manager 会发{gen_event_EXIT,Handler,Reason}给进程(the calling process):这时的Reason会有以下:

  • 1)normal ----使用delete_handler/3或remove_handler
  • 2)shutdown ---event_manager 终结了:is terminating
  • 3){swapped,NewHandler,Pid} 如果使用swap_handler/3或swap_sup_handler/3替换原event handler
  • 4)一个term如果由于一个错误被移除

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

notify(EventMgrRef, Event) -> ok

sync_notify(EventMgrRef, Event) -> ok

Types:
EventMgrRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()
Event = term()

向已增加在event manager里面所有的event handler都发一个Event(MSG).event manager会调用所有的event handler的Module:handler_event/2.
    notify 是异步的:在消息发出后立即返回,sync_notify同步的,会在所有的event_handler处理完消息后返回ok.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

call(EventMgrRef, Handler, Request) -> Result
call(EventMgrRef, Handler, Request, Timeout) -> Result Types: EventMgrRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()
Handler = Module | {Module,Id}
Module = atom()
Id = term()
Request = term()
Timeout = int()>0 | infinity
Result = Reply | {error,Error}
Reply = term()
Error = bad_module | {'EXIT',Reason} | term()
Reason = term()

一个同步call(和gen_server:call差不多)不过会指定对应的Hander来处理Request.Handler内使用handler_call/2来处理Request.
    TimeOut 是一个比0大的毫秒级或infinity.默认值为50000ms.如果规定时间内没有返回,就会call fails.
   
Repeal会返回Module:handle_call/2返回,如果 event
handler没有安装,会返回{error,bad_module}.callback会分别返回Reason Term
,这个函数就会返回{error,{'EXIT',Reason},{error,Term}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

delete_handler(EventMgrRef, Handler, Args) -> Result

Types:
EventMgrRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()
Handler = Module | {Module,Id}
Module = atom()
Id = term()
Args = term()
Result = term() | {error,module_not_found} | {'EXIT',Reason}
Reason = term()

删除event manager(EvenMgrRef)里面对应的Handler,调用Handler:terminate(Args,State).来终结这个事件.
Result:返回Handler:terminate(Args,State)的返回值,如果没有找到安装的事件返回{error,module_not_found}.
   如果失败了就会回调返回Reason.此函数返回:{'EXIT',Reason}.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

swap_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result

Types:
EventMgrRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()
Handler1 = Handler2 = Module | {Module,Id}
Module = atom()
Id = term()
Args1 = Args2 = term()
Result = ok | {error,Error}
Error = {'EXIT',Reason} | term()
Reason = term()

在event manager (EventMgrRef)用Handler1代替Handler2

  • 1)删除Handler1-----与调用delete_handler一致:
  • 2)增加Handler2-----与调用add_handler一致:【init里面调用{Args2,Term}:Term是Handler1:terminate里面返回的】
  • 3)这2个操作没有原子性,1,2的成功没有关系的。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

swap_sup_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result

Types:
EventMgrRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()
Handler1 = Handler 2 = Module | {Module,Id}
Module = atom()
Id = term()
Args1 = Args2 = term()
Result = ok | {error,Error}
Error = {'EXIT',Reason} | term()
Reason = term()

与swap_handler/3一致,但是会Handler2和the calling process里面建立连接.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

which_handlers(EventMgrRef) -> [Handler]

Types:
EventMgrRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()
Handler = Module | {Module,Id}
Module = atom()
Id = term()

返回event manager的事件Event handler列表
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

stop(EventMgrRef) -> ok

Types:
EventMgrRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()

terminates the event manager 在此之前会对安装好的事件调用Module:terminate(stop,...).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
event handler里面的callback函数

Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate} | {error,Reason}
Types:
InitArgs = Args | {Args,Term}
Args = Term = term()
State = term()
Reason = term()

当一个新的event handler被加入event manager时,这个函数会被调用.
    调用gen_event:add_sup_handler/3,swap_handler/3 swap_sup_handler
    返回{ok,State,hibernate}时event manager会进入休眠状态:等待下次事件发生

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Module:handle_event(Event, State) -> Result

Types:
Event = term()
State = term()
Result = {ok,NewState} | {ok,NewState,hibernate} | {swap_handler,Args1,NewState,Handler2,Args2} | remove_handler
NewState = term()
Args1 = Args2 = term()
Handler2 = Module2 | {Module2,Id}
Module2 = atom()
Id = term

当event manager收到用notify/2或sync_notify/2发送的消息时会调用:所有安装过的事件的Handler:handler_event/2
    
返回{swap_handler,Args1,NewState,Handler2,Args2}时会调用Term =
Module:terminate(Args1,NewState),Module2:init(Args2,Term)
【基本和swap_handler/3相同】
     返回remove_handler 时会调用Module:terminate(remove_handler,State).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Module:handle_call(Request, State) -> Result

Types:
Request = term()
State = term()
Result = {ok,Reply,NewState} | {ok,Reply,NewState,hibernate}| {swap_handler,Reply,Args1,NewState,Handler2,Args2}| {remove_handler, Reply}
Reply = term()
NewState = term()
Args1 = Args2 = term()
Handler2 = Module2 | {Module2,Id}
Module2 = atom()
Id = term()

使用gen_event:call/3发出的信息,与handle_event类似,不过是同步的。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Module:handle_info(Info, State) -> Result

Types:
Info = term()
State = term()
Result = {ok,NewState} | {ok,NewState,hibernate}
| {swap_handler,Args1,NewState,Handler2,Args2} | remove_handler
NewState = term()
Args1 = Args2 = term()
Handler2 = Module2 | {Module2,Id}
Module2 = atom()
Id = term()

收到除用gen_event:call/3,gen_event:notify/3,gen_event:sync_notify/3之外的任何消息。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Module:terminate(Arg, State) -> term()

Types:
Arg = Args | {stop,Reason} | stop | remove_handler
| {error,{'EXIT',Reason}} | {error,Term}
Args = Reason = Term = term()

在要完成删除,清理工作时会调用。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Module:code_change(OldVsn, State, Extra) -> {ok, NewState}

Types:
OldVsn = Vsn | {down, Vsn}
Vsn = term()
State = NewState = term()
Extra = term()

Erlang OTP gen_event的更多相关文章

  1. [Erlang 0119] Erlang OTP 源码阅读指引

      上周Erlang讨论群里面提到lists的++实现,争论大多基于猜测,其实打开代码看一下就都明了.贴出代码截图后有同学问这代码是哪里找的?   "代码去哪里找?",关于Erla ...

  2. Erlang/OTP设计原则(文档翻译)

    http://erlang.org/doc/design_principles/des_princ.html 图和代码皆源自以上链接中Erlang官方文档,翻译时的版本为20.1. 这个设计原则,其实 ...

  3. 理解Erlang/OTP Supervisor

    http://www.cnblogs.com/me-sa/archive/2012/01/10/erlang0030.html Supervisors are used to build an hie ...

  4. [Erlang 0127] Term sharing in Erlang/OTP 上篇

    之前,在 [Erlang 0126] 我们读过的Erlang论文 提到过下面这篇论文: On Preserving Term Sharing in the Erlang Virtual Machine ...

  5. CentOS 6.5安装Erlang/OTP 17.0

    CentOS 6.5安装Erlang/OTP 17.0 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs Erlang眼下已经是Fedora和Debian/ ...

  6. Erlang/OTP:基于Behaviour的回调函数

    原始链接:https://blog.zhustec.me/posts/erlang-otp-1-callback-based-on-behaviour OTP 是什么 OTP 的全称是开源电信平台 ( ...

  7. Erlang OTP设计原则Gen_Fsm行为[转]

    转自: http://www.cnblogs.com/yourihua/archive/2012/05/13/2497776.html 1. Fsm 称为 有限状态机,举个例子,游戏中的怪物称为NPC ...

  8. 理解Erlang/OTP - Application

    http://www.cnblogs.com/me-sa/archive/2011/12/27/erlang0025.html 1>application:start(log4erl). 我们就 ...

  9. Erlang OTP编程初体验——gen_server和行为模式

    http://blog.sina.com.cn/s/blog_3fe961ae0101k4p6.html 行为模式其实非常类似于面向对象语言中的接口,至少笔者是这么理解的.OTP行为模式将一些反复出现 ...

随机推荐

  1. Webkit浏览器点击控件时出现的边框消除

    -webkit-tap-highlight-color:rgba(0,0,0,0); 其实是将边框颜色透明,让其不可见了而已

  2. 博客搬到CSDN了,以后就老实的呆在这儿吧~~

    几年前读书的时候就自己在做独立的个人博客网站,重做 + 改版好多次,域名也换了好几个- 163fly.com.godbz.com.zhouz.me ... 都是我曾经用过的域名,都放弃了- 发现到头来 ...

  3. 分布式存储 CentOS6.5虚拟机环境搭建FastDFS-5.0.5集群(转载-2)

    原文:http://www.cnblogs.com/PurpleDream/p/4510279.html 分布式存储 CentOS6.5虚拟机环境搭建FastDFS-5.0.5集群 前言:       ...

  4. jdk7 HashSet和HashMap源码分析

    先来看看HashMap的一些成员变量以及他们的含义 /** * The default initial capacity - MUST be a power of two. */ static fin ...

  5. AJAX在Struts2中使用

    前台页面: <%@ page language="java" contentType="text/html; charset=UTF-8" pageEnc ...

  6. S.O.L.I.D五大原则之单一职责SRP

    转自 : 汤姆大叔的blog Bob大叔提出并发扬了S.O.L.I.D五大原则,用来更好地进行面向对象编程,五大原则分别是: The Single Responsibility Principle(单 ...

  7. curl的简单使用步骤

    要使用cURL来发送url请求,具体步骤大体分为以下四步: 1.初始化2.设置请求选项3.执行一个cURL会话并且获取相关回复4.释放cURL句柄,关闭一个cURL会话 // 1. 初始化一个cURL ...

  8. CVE-2014-1767 利用分析(2015.2)

    CVE-2014-1767利用分析 参考这篇文章利用思路,重现利用,主要说明自己在实现的时候遇到的坑. 利用思路 1. 第一次 IoControl,释放 MDL,我们通过 VirtualAddress ...

  9. GO interface显示类型转换方法

    一共两种,直接看代码 import ( "fmt") func main() { //var i interface{} = "TT" var i interf ...

  10. ajaxUploadFile在IE9等IE浏览器,上传变json下载的问题解决(SpringMVC + ajaxUploadFile)

    使用ajaxUploadFIle进行文件上传,在google中正常,但是IE中却变成了json文件下载.经过搜索和尝试,解决方案如下: 首先明确,该功能使用$.ajaxFileUpload而非ajax ...