gen_event
gen_event
模块
gen_event
模块摘要
一般事件处理行为。
描述
此行为模块提供事件处理功能。它由一个通用事件管理器进程组成,其中包含动态添加和删除的任意数量的事件处理程序。
使用此模块实现的事件管理器具有一组标准的接口函数,并包含用于跟踪和错误报告的功能。它也适合于OTP监督树。有关更多信息,请参阅OTP Design Principles
。
每个事件处理程序都被实现为一个回调模块,用于导出一组预定义的函数。行为函数和回调函数之间的关系如下所示:
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
由于每个事件处理程序都是一个回调模块,因此事件管理器具有许多动态添加和删除的回调模块。 因此,gen_event比其他行为更容忍回调模块错误。 如果安装的事件处理程序的回调函数由于Reason而失败,或者返回错误的Term值,则事件管理器不会失败。 它通过调用callback函数Module:terminate / 2,分别给出参数{error,{'EXIT',Reason}}或{error,Term}来删除事件处理程序。 其他事件处理程序不受影响。
一个gen_event
进程处理系统消息,如下所述sys(3)
。该sys
模块可用于调试事件管理器。
请注意,事件管理器会
自动捕获退出信号。
该gen_event
过程可以进入休眠状态(见erlang:hibernate/3
),如果处理模块中的回调函数指定hibernate
其返回值。如果服务器预计长时间处于空闲状态,这可能很有用。但是,请谨慎使用此功能,因为休眠意味着至少有两个垃圾回收(休眠时和稍后唤醒后),而且不是您想在忙事件管理器处理的每个事件之间执行的操作。
注意,当调用多个事件处理程序时,一个事件处理程序返回hibernate
请求整个事件经理进入休眠状态。
除非另有说明,否则如果指定的事件管理器不存在或指定了错误的参数,则此模块中的所有函数都会失败。
数据类型
handler() = atom() | {atom(), term()}
handler_args() = term()
add_handler_ret() = ok | term() | {'EXIT', term()}
del_handler_ret() = ok | term() | {'EXIT', term()}
输出
add_handler(EventMgrRef, Handler, Args) -> Result
类型
向事件管理器添加新的事件处理程序EventMgrRef
。事件管理器调用Module:init/1
以启动事件处理程序及其内部状态。
EventMgrRef
可以是下列任何一种:
- PID
Name
,如果事件管理器是本地注册的。
{Name,Node}
,如果事件管理器是在另一个节点本地注册的。
{global,GlobalName}
,如果事件管理器是全局注册的。
{via,Module,ViaName}
,如果事件管理器是通过另一个流程注册表注册的。
Handler
是回调模块Module
或元组的名称{Module,Id}
,其中Id
是任何术语。该{Module,Id}
表示使得当许多事件处理程序使用相同的回调模块可以识别特定的事件处理程序。
Args
作为参数传递给Module:init/1
...
如果Module:init/1
返回表示成功完成的正确值,则事件管理器将添加事件处理函数,并返回此函数ok
。如果Module:init/1
失败Reason
或返回{error,Reason}
,事件处理程序将被忽略,并且此函数分别返回{'EXIT',Reason}
或{error,Reason}
。
add_sup_handler(EventMgrRef, Handler, Args) -> Result
类型
按照相同的方式添加新的事件处理程序add_handler/3
,但也监视事件处理程序和调用过程之间的连接。
- 如果稍后调用进程终止
Reason
,则事件管理器通过Module:terminate/2
以{stop,Reason}
参数调用来删除事件处理程序。
- 如果事件处理程序稍后被删除,则事件管理器将发送一条消息。
{gen_event_EXIT,Handler,Reason}
呼叫进程。Reason
为下列之一:
- `normal`, if the event handler has been removed because of a call to `delete_handler/3`, or `remove_handler` has been returned by a callback function (see below).
- `shutdown`, if the event handler has been removed because the event manager is terminating.
- `{swapped,NewHandler,Pid}`, if the process `Pid` has replaced the event handler with another event handler `NewHandler` using a call to [`swap_handler/3`](about:blank#swap_handler-3) or [`swap_sup_handler/3`](about:blank#swap_sup_handler-3).
- A term, if the event handler is removed because of an error. Which term depends on the error.
有关参数和返回值的说明,请参见add_handler/3
...
call(EventMgrRef, Handler, Request) -> Resultcall(EventMgrRef, Handler, Request, Timeout) -> Result
类型
对事件处理程序进行同步调用。Handler
安装在事件管理器中EventMgrRef
通过发送请求并等待回复到达或超时。事件管理器调用Module:handle_call/2
来处理请求。
有关说明EventMgrRef
和Handler
见add_handler/3
。
Request
作为参数之一传递给Module:handle_call/2
...
Timeout
是一个大于零的整数,用于指定等待答复的毫秒数或原子infinity
无限期等待的时间。默认为5000.如果在指定的时间内没有收到回复,则函数调用失败。
返回值Reply
是在返回值中定义的Module:handle_call/2
。如果未安装指定的事件处理程序,则函数返回{error,bad_module}
。如果回调函数失败并Reason
返回意外值Term
,则此函数分别返回{error,{'EXIT',Reason}}
或{error,Term}
。
delete_handler(EventMgrRef, Handler, Args) -> Result
类型
从事件管理器中删除事件处理程序。EventMgrRef
事件管理器调用Module:terminate/2
若要终止事件处理程序,请执行以下操作。
有关说明EventMgrRef
和Handler
见add_handler/3
。
Args
作为参数之一传递给Module:terminate/2
...
返回值是返回值Module:terminate/2
。如果未安装指定的事件处理程序,则函数返回{error,module_not_found}
。如果回调函数失败Reason
,函数返回{'EXIT',Reason}
。
notify(EventMgrRef, Event) -> oksync_notify(EventMgrRef, Event) -> ok
类型
向事件管理器发送事件通知EventMgrRef
。事件管理器要求Module:handle_event/2
每个安装的事件处理程序来处理事件。
notify / 2是异步的,并在发送事件通知后立即返回。 sync_notify / 2是同步的,因为在事件被所有事件处理程序处理后,它返回ok。
有关说明EventMgrRef
,请参阅add_handler/3
。
Event
作为参数之一传递给Module:handle_event/2
...
notify/1
即使指定的事件管理器不存在,也不会失败,除非它被指定为Name
。
start() -> Resultstart(EventMgrName | Options) -> Resultstart(EventMgrName, Options) -> Result
类型
创建一个独立的事件管理器进程,也就是说,事件管理器不是监督树的一部分,因此没有监督者。
有关参数和返回值的说明,请参见start_link/0,1
...
start_link() -> Resultstart_link(EventMgrName | Options) -> Resultstart_link(EventMgrName, Options) -> Result
类型
创建事件管理器进程作为监视树的一部分。该职能由主管直接或间接地调用。例如,它确保事件管理器链接到主管。
- 如果
EventMgrName={local,Name}
,事件管理器在本地注册为Name
使用register/2
。
- 如果EventMgrName = {global,GlobalName},则使用global:register_name / 2将事件管理器全局注册为GlobalName。 如果没有提供名称,则事件管理器未注册。
- 如果EventMgrName = {via,Module,ViaName},则事件管理器向Module注册的注册表注册。 Module回调函数是导出函数register_name / 2,unregister_name / 1,whereis_name / 1和send / 2,这些函数在全局中表现为相应的函数。 因此,{via,global,GlobalName}是一个有效的参考。
- 如果
{hibernate_after,HibernateAfterTimeout}
存在选项,则gen_event
进程等待任何消息HibernateAfterTimeout
几毫秒,如果没有收到消息,进程将自动进入休眠状态(通过调用proc_lib:hibernate/3
)。
如果事件管理器成功创建,则函数返回{ok,Pid},其中Pid是事件管理器的pid。 如果已经存在指定EventMgrName的进程,则函数返回{error,{already_started,Pid}},其中Pid是该进程的PID。
stop(EventMgrRef) -> okstop(EventMgrRef, Reason, Timeout) -> ok
类型
订单事件管理EventMgrRef
器用指定退出Reason
并等待它终止。在终止之前,gen_event
调用Module:terminate(stop,...)
每个已安装的事件处理程序。
如果事件管理器以期望的原因终止,则该函数返回OK。 除正常,关机或{shutdown,Term}之外的任何其他原因都会导致使用error_logger:format / 2发出错误报告。 默认原因是正常的。
Timeout
是一个大于零的整数,指定等待事件管理器终止多少毫秒,或者infinity
无限期等待原子。默认为infinity
。如果事件管理器在指定时间内没有终止,timeout
则会引发异常。
如果进程不存在,则引发异常noproc
。
有关说明EventMgrRef
,请参阅add_handler/3
。
swap_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result
类型
在事件管理器中用新的事件处理程序替换旧的事件处理程序EventMgrRef
。
有关参数的描述,请参见add_handler/3
...
首先Handler1
删除旧的事件处理程序。事件管理器调用Module1:terminate(Args1, ...)
,这里Module1
是回调模块Handler1
,并收集返回值。
然后Handler2
通过调用来添加和启动新的事件处理程序Module2:init{Args2,Term}),
其中Module2回
调模块的Handler2
和Term是
返回值Module1:terminate/2。
这可以将信息从Handler1到
Handler2
。
即使没有安装指定的旧事件处理程序,也会添加新的处理程序。Term=error
,或者如果Module1:terminate/2
失败Reason
,在这种情况下Term={'EXIT',Reason}
删除旧的处理程序,即使Module2:init/1
失败了。
如果在Handler1
和一个过程Pid
,之间有一个有监督的联系。Handler2
和Pid
相反。
如果Module2:init / 1返回正确的值,则此函数返回ok。 如果Module2:init / 1因Reason失败或返回意外值Term,则此函数分别返回{error,{'EXIT',Reason}}或{error,Term}。
swap_sup_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result
类型
在事件管理器EventMgrRef
中以与之相同的方式替换事件处理程序swap_handler/3
,但也监视Handler2
与调用过程之间的连接。
有关参数和返回值的说明,请参见swap_handler/3
...
which_handlers(EventMgrRef) -> [Handler]
类型
返回事件管理器中安装的所有事件处理程序的列表EventMgrRef
。
有关说明EventMgrRef
和Handler
见add_handler/3
。
回调函数
下面的函数将从gen_event
回调模块。
输出
Module:code_change(OldVsn, State, Extra) -> {ok, NewState}
类型
注
这个回调是可选的,所以回调模块不需要导出它。如果Change={advanced,Extra}
在未实现的情况下执行.appup
文件中指定的版本升级/降级,code_change/3
则事件处理程序将因undef
错误原因而崩溃。
此函数针对安装的事件处理程序调用,该处理程序在发行版升级/降级期间更新其内部状态,即在文件中指定指令{update,Module,Change,...}
where 时。有关更多信息,请参阅Change={advanced,Extra}.appupOTP Design Principles
对于升级,OldVsn是Vsn,对于降级,OldVsn是{down,Vsn}。 Vsn由回调模块Module的旧版本的vsn属性定义。 如果未定义此类属性,则版本是Beam文件的校验和。
State
事件处理程序的内部状态。
Extra
从{advanced,Extra}
更新指令的一部分。
函数是返回更新的内部状态。
Module:format_status(Opt, [PDict, State]) -> Status
类型
注
此回调是可选的,因此事件处理程序模块不需要导出它。如果处理程序不导出此函数,则gen_event
模块直接将处理程序状态用于以下目的。
此函数由gen_event
在下列情况下处理:
- sys之一:get_status / 1,2被调用以获得gen_event状态。 对于这种情况,Opt被设置为正常原子。
- 事件处理程序异常终止,并且
gen_event
记录错误。Opt
被设置为原子terminate
为了这个案子。
此函数对于更改这些情况下事件处理程序状态的形式和外观很有用。事件处理程序回调模块希望更改sys:get_status/1,2
返回值以及其状态在终止错误日志中的显示方式,导出一个实例format_status/2
返回描述事件处理程序当前状态的术语。
PDict
是过程字典的当前值gen_event
。
State
事件处理程序的内部状态。
该函数返回Status
一个改变事件处理程序当前状态细节的术语。任何术语都是允许的Status
。该gen_event
模块使用Status
如下:
- 何时
sys:get_status/1,2
被调用,gen_event
确保其返回值包含Status
事件处理程序的状态项。
- 当事件处理程序异常终止时,
gen_event
将记录事件处理程序Status
的状态项。
此功能的一个用途是返回紧凑的替代状态表示,以避免在日志文件中打印大型状态项。
Module:handle_call(Request, State) -> Result
类型
每当事件管理器收到使用call/3,4
,则为指定的事件处理程序调用此函数以处理请求。
Request
是Request
争论call/3,4
...
State
事件处理程序的内部状态。
返回值与Module:handle_event / 2的返回值相同,除了它们还包含一个术语Reply,它是作为调用/ 3,4的返回值对客户端的答复。
Module:handle_event(Event, State) -> Result
类型
每当事件管理器接收到使用notify/2
or 发送的事件时sync_notify/2
,就会为每个安装的事件处理程序调用此函数来处理事件。
Event是notify / 2 / sync_notify / 2的Event参数。
State
事件处理程序的内部状态。
- 如果{ok,NewState}或{ok,NewState,hibernate}被返回,则事件处理程序保持在事件管理器中,并且可能更新内部状态NewState。
- 如果
{ok,NewState,hibernate}
返回,事件管理器也会通过调用进入休眠状态proc_lib:hibernate/3
,等待下一个事件发生。只要其中一个事件处理程序返回{ok,NewState,hibernate}
整个事件管理器进程即可休眠。
- 如果
{swap_handler,Args1,NewState,Handler2,Args2}
返回,则事件处理程序Handler2
由第一次调用替换Module:terminate(Args1,NewState)
,然后Module2:init{Args2,Term}),
Term返
回值为Module:terminate/2。
有关更多信息,请参阅swap_handler/3。
- 如果
remove_handler
返回时,将通过以下方式删除事件处理程序:Module:terminate(remove_handler,State)
...
Module:handle_info(Info, State) -> Result
类型
注
这个回调是可选的,所以回调模块不需要导出它。该gen_event
模块提供了该功能的默认实现,该实现记录了意外Info
消息,并将其丢弃并返回{noreply, State}
。
当事件管理器收到除事件或同步请求(或系统消息)之外的任何其他消息时,将为每个已安装的事件处理程序调用此函数。
Info
是接收到的消息。
有关State
可能的返回值的说明,请参阅Module:handle_event/2
。
Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate} | {error,Reason}
类型
每当向事件管理器添加新的事件处理程序时,都会调用此函数来初始化事件处理程序。
如果事件处理程序是因为调用add_handler/3
or 而添加的add_sup_handler/3
,InitArgs
则Args
这些函数的参数。
如果事件处理程序由于调用swap_handler / 3或swap_sup_handler / 3或由于其他回调函数之一的交换返回元组而替换另一个事件处理程序,则InitArgs是一个元组{Args,Term},其中Args是 参数在函数调用/返回元组中提供,Term是终止旧事件处理程序的结果,请参阅swap_handler / 3。
如果成功,则函数返回{ok,State}
或{ok,State,hibernate}
,其中State
是事件处理程序的初始内部状态。
如果{ok,State,hibernate}
返回,则事件管理器进入休眠状态(通过调用proc_lib:hibernate/3
),等待下一个事件发生。
Module:terminate(Arg, State) -> term()
类型
注
这个回调是可选的,所以回调模块不需要导出它。该gen_event
模块提供了一个没有清理的默认实现。
每当从事件管理器中删除事件处理程序时,都会调用此函数。它将是与之相反的Module:init/1
做任何必要的清理。
如果事件处理程序,因为一个电话而被删除到delete_handler/3
,swap_handler/3
或者swap_sup_handler/3
,Arg
是Args
这个函数调用的参数。
Arg={stop,Reason}
如果事件处理程序具有监督连接到已经以理由终止的进程Reason
。
Arg=stop
如果事件处理程序因事件管理器正在终止而被删除。
如果事件管理器是监督树的一部分,并且由其主管命令终止,则事件管理器将终止。即使是不
监视树的一部分,如果接收到'EXIT'
它的父消息。
Arg=remove_handler
如果由于另一个回调函数返回而删除了事件处理程序remove_handler
或{remove_handler,Reply}
...
Arg={error,Term}
如果由于回调函数返回意外值而删除事件处理程序Term
,或Arg={error,{'EXIT',Reason}}
如果回调函数失败。
State
事件处理程序的内部状态。
函数可以返回任何术语。如果事件处理程序由于调用gen_event:delete_handler/3
,则该函数的返回值将变为此函数的返回值。如果由于交换而将事件处理程序替换为另一个事件处理程序,则返回值将传递给init
新事件处理程序的函数。否则,将忽略返回值。
另见
supervisor(3)
,sys(3)