查看源代码 gen_event 行为 (stdlib v6.2)

通用事件处理行为。

此行为模块提供事件处理功能。它由一个通用事件管理器进程和任意数量的动态添加和删除的事件处理程序组成。

使用此模块实现的事件管理器具有一组标准的接口函数,并包含跟踪和错误报告的功能。它也适合 OTP 监督树。有关详细信息,请参阅 OTP 设计原则

每个事件处理程序都实现为一个回调模块,该模块导出一组预定义的函数。行为函数和回调函数之间的关系如下

gen_event module                   Callback module
----------------                   ---------------
gen_event:start
gen_event:start_monitor
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:send_request
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,则事件管理器不会失败。它会通过调用回调函数 Module:terminate/2 来删除事件处理程序,并分别以 {error, {'EXIT', Reason}}{error, Term} 作为参数。其他事件处理程序不受影响。

gen_event 进程按照 sys 中所述处理系统消息。sys 模块可用于调试事件管理器。

请注意,事件管理器自动捕获退出信号。

如果处理程序模块中的回调函数在其返回值中指定了 hibernate,则 gen_event 进程可以进入休眠状态(请参阅 erlang:hibernate/3)。如果服务器预计会空闲很长时间,这会很有用。但是,请谨慎使用此功能,因为休眠意味着至少两次垃圾回收(在休眠时和唤醒后不久),并且不希望在繁忙的事件管理器处理的每个事件之间执行此操作。

请注意,当调用多个事件处理程序时,只要一个事件处理程序返回 hibernate 请求,就足以使整个事件管理器进入休眠状态。

除非另有说明,否则如果指定的事件管理器不存在或指定了错误的参数,则此模块中的所有函数都会失败。

注意

有关分布式信号的一些重要信息,请参阅 Erlang 参考手册进程章节中的通过分布式阻塞信号部分。阻塞信号可能导致例如 gen_event 中的调用超时明显延迟。

另请参阅

supervisor, sys

概要

类型

事件管理器名称规范:localglobalvia 注册。

用于定位事件管理器的引用。

描述 gen_event 进程状态的映射。

可用于配置事件处理程序在启动时使用的选项。

不透明的请求标识符。有关详细信息,请参阅 send_request/3

不透明的请求标识符集合(request_id/0)。

异步调用的响应超时。

回调

在代码更改后更新事件处理程序状态。

格式化/限制状态值。

格式化/限制状态值。

处理调用。

处理事件。

处理信息消息(常规进程消息)。

初始化事件处理程序。

处理事件处理程序终止。

函数

向事件管理器添加新的事件处理程序。

向事件管理器添加新的事件处理程序,并进行监督。

对事件处理程序进行同步调用。

检查接收到的消息是否为请求响应。

检查接收到的消息是否为集合中的请求响应。

从事件管理器删除事件处理程序。

向事件管理器发送异步事件通知。

接收请求响应。

接收集合中的请求响应。

将请求标识符存储在集合中。

创建空的请求标识符集合。

返回 ReqIdCollection 中的请求标识符的数量。

将请求标识符集合转换为列表。

向事件处理程序发送异步 call 请求。

向事件处理程序发送异步 call 请求,并将其存储在请求标识符集合中。

等效于 start([])

创建独立的事件管理器进程,可能无名。

创建独立的事件管理器进程。

创建事件管理器进程作为监督树的一部分,可能无名。

创建事件管理器进程作为监督树的一部分。

创建独立的事件管理器进程,受到监控,可能无名。

创建独立的事件管理器进程,受到监控。

停止事件管理器。

替换事件处理程序,并进行监督。

向事件管理器发送同步事件通知。

等待请求响应。

等待集合中的任何请求响应。

返回事件管理器中的所有事件处理程序。

类型

-type add_handler_ret() :: ok | term() | {'EXIT', term()}.
链接到此类型

debug_flag()

查看源代码 (未导出)
-type debug_flag() :: trace | log | statistics | debug | {logfile, string()}.
-type del_handler_ret() :: ok | term() | {'EXIT', term()}.
链接到此类型

emgr_name()

查看源代码 (未导出)
-type emgr_name() :: {local, atom()} | {global, term()} | {via, atom(), term()}.

事件管理器名称规范:localglobalvia 注册。

  • {local, Name} - 事件管理器在本地注册为 Name,使用 register/2
  • {global, GlobalName} - 事件管理器在全局注册为 GlobalName,使用 global:register_name/2。如果未提供名称,则事件管理器不注册。
  • {via, Module, ViaName},事件管理器在由 Module 表示的注册表中注册。Module 回调应导出函数 register_name/2unregister_name/1whereis_name/1send/2,其行为应与 global 中的相应函数相同。因此,{via, global, GlobalName} 是有效的引用。
链接到此类型

emgr_ref()

查看源代码 (未导出)
-type emgr_ref() :: atom() | {atom(), node()} | {global, term()} | {via, atom(), term()} | pid().

用于定位事件管理器的引用。

引用可以是以下任何一种

  • 事件管理器的 pid
  • Name,如果事件管理器在本地注册
  • {Name, Node},如果事件管理器在另一个节点上本地注册
  • {global, GlobalName},如果事件管理器在全局注册
  • {via, Module, ViaName},如果事件管理器通过替代进程注册表注册
-type format_status() ::
          #{state => term(), message => term(), reason => term(), log => [sys:system_event()]}.

描述 gen_event 进程状态的映射。

键是

  • state - 事件处理程序的内部状态。
  • message - 导致事件处理程序终止的消息。
  • reason - 导致事件处理程序终止的原因。
  • log - 服务器的 sys 日志

新的关联可能会在没有事先通知的情况下添加到状态映射中。

-type handler() :: atom() | {atom(), term()}.
-type handler_args() :: term().
-type options() ::
          [{timeout, timeout()} |
           {debug, [debug_flag()]} |
           {spawn_opt, [proc_lib:start_spawn_option()]} |
           {hibernate_after, timeout()}].

可用于配置事件处理程序在启动时使用的选项。

-opaque request_id()

不透明的请求标识符。有关详细信息,请参阅 send_request/3

-opaque request_id_collection()

不透明的请求标识符集合(request_id/0)。

每个请求标识符都可以与用户选择的标签关联。有关更多信息,请参阅 reqids_new/0

链接到此类型

response_timeout()

查看源码 (未导出)
-type response_timeout() :: timeout() | {abs, integer()}.

异步调用的响应超时。

用于设置等待响应的时间限制,可以使用 receive_response/2receive_response/3wait_response/2wait_response/3。使用的时间单位是 millisecond。当前有效值

  • 0..4294967295 - 相对于当前时间的超时(以毫秒为单位)。

  • infinity - 无限超时。也就是说,操作永远不会超时。

  • {abs, Timeout} - 绝对 Erlang 单调时间超时(以毫秒为单位)。也就是说,当 erlang:monotonic_time(millisecond) 返回的值大于或等于 Timeout 时,操作将超时。不允许 Timeout 指定比 4294967295 毫秒更远的未来时间。当您有一个与完整请求集合 (request_id_collection/0) 相对应的响应截止日期时,使用绝对超时值来标识超时特别方便,因为您不必一遍又一遍地重新计算截止日期之前的相对时间。

链接到此类型

start_mon_ret()

查看源码 (未导出)
-type start_mon_ret() :: {ok, {pid(), reference()}} | {error, term()}.
链接到此类型

start_ret()

查看源码 (未导出)
-type start_ret() :: {ok, pid()} | {error, term()}.

回调

链接到此回调

code_change(OldVsn, State, Extra)

查看源码 (可选)
-callback code_change(OldVsn :: term() | {down, term()}, State :: term(), Extra :: term()) ->
                         {ok, NewState :: term()}.

在代码更改后更新事件处理程序状态。

当在发布升级/降级期间(即,当 appup 文件中指定指令 {update, Module, Change,...} 时),为已安装的事件处理程序调用此函数以更新其内部状态。

有关更多信息,请参阅 OTP 设计原则

对于升级,OldVsnVsn,对于降级,OldVsn{down, Vsn}Vsn 由回调模块 Module 的旧版本的 vsn 属性定义。如果未定义此类属性,则版本是 Beam 文件的校验和。

State 是事件处理程序的内部状态。

Extra 从更新指令的 {advanced, Extra} 部分“按原样”传递。

该函数应返回更新后的内部状态。

注意

如果在 .appup 文件中指定了 Change={advanced, Extra} 的发布升级/降级时,未实现 code_change/3,则事件处理程序将因 undef 错误原因而崩溃。

链接到此回调

format_status(Status)

查看源码 (可选) (自 OTP 25.0 起)
-callback format_status(Status) -> NewStatus when Status :: format_status(), NewStatus :: format_status().

格式化/限制状态值。

此函数由 gen_event 进程调用,以便格式化/限制服务器状态以进行调试和日志记录。

在以下情况下调用它

  • 调用 sys:get_status/1,2 之一来获取 gen_event 状态。

  • 事件处理程序异常终止,并且 gen_event 记录错误。

此回调用于限制由 sys:get_status/1,2 返回或发送到 logger 的事件处理程序的状态。

回调获取一个描述当前状态的映射 Status,并应返回一个具有相同键的映射 NewStatus,但它可以转换某些值。

此回调的两个可能用例是从状态中删除敏感信息,以防止其打印在日志文件中,或者压缩仅会使日志混乱的大型无关状态项。

示例:

format_status(Status) ->
  maps:map(
    fun(state,State) ->
            maps:remove(private_key, State);
       (message,{password, _Pass}) ->
            {password, removed};
       (_,Value) ->
            Value
    end, Status).

注意

此回调是可选的,因此事件处理程序模块不需要导出它。如果处理程序未导出此函数,则 gen_event 模块将直接使用处理程序状态来实现以下描述的目的。

如果导出此回调但失败,为了隐藏可能敏感的数据,默认函数将改为返回 format_status/1 已崩溃的事实。

链接到此回调

format_status(Opt, StatusData)

查看源码 (可选) (自 OTP R14B 起)
此回调已弃用。回调 gen_event:format_status(_,_ ) 已弃用; 请改用 format_status/1。
-callback format_status(Opt, StatusData) -> Status
                           when
                               Opt :: normal | terminate,
                               StatusData :: [PDict | State],
                               PDict :: [{Key :: term(), Value :: term()}],
                               State :: term(),
                               Status :: term().

格式化/限制状态值。

此函数由 gen_event 进程调用,以便格式化/限制服务器状态以进行调试和日志记录。

在以下情况下调用它

  • 调用 sys:get_status/1,2 之一来获取 gen_event 状态。在这种情况下,Opt 设置为原子 normal

  • 事件处理程序异常终止,并且 gen_event 记录错误。在这种情况下,Opt 设置为原子 terminate

此函数对于更改这些情况下事件处理程序状态的形式和外观很有用。希望更改 sys:get_status/1,2 返回值以及其状态在终止错误日志中的显示方式的事件处理程序回调模块,将导出 format_status/2 的实例,该实例返回描述事件处理程序当前状态的项。

PDictgen_event 进程字典的当前值。

State 是事件处理程序的内部状态。

该函数应返回 Status,一个更改事件处理程序当前状态详细信息的项。任何项都允许作为 Statusgen_event 模块按以下方式使用 Status

  • 当调用 sys:get_status/1,2 时,gen_event 确保其返回值包含 Status,而不是事件处理程序的状态项。

  • 当事件处理程序异常终止时,gen_event 将在事件处理程序的状态项的位置记录 Status

此函数的一个用途是返回紧凑的替代状态表示形式,以避免在日志文件中打印大型状态项。

注意

此回调是可选的,因此事件处理程序模块不需要导出它。如果处理程序未导出此函数,则 gen_event 模块将直接使用处理程序状态来实现以下描述的目的。

链接到此回调

handle_call(Request, State)

查看源代码
-callback handle_call(Request :: term(), State :: term()) ->
                         {ok, Reply :: term(), NewState :: term()} |
                         {ok, Reply :: term(), NewState :: term(), hibernate} |
                         {swap_handler,
                          Reply :: term(),
                          Args1 :: term(),
                          NewState :: term(),
                          Handler2 :: atom() | {atom(), Id :: term()},
                          Args2 :: term()} |
                         {remove_handler, Reply :: term()}.

处理调用。

每当事件管理器收到使用 call/3,4 发送的请求时,将为指定的事件处理程序调用此函数以处理该请求。

Requestcall/3,4Request 参数。

State 是事件处理程序的内部状态。

返回值与 Module:handle_event/2 的返回值相同,但它们还包含项 Reply,它是作为 call/3,4 的返回值的客户端回复。

链接到此回调

handle_event(Event, State)

查看源代码
-callback handle_event(Event :: term(), State :: term()) ->
                          {ok, NewState :: term()} |
                          {ok, NewState :: term(), hibernate} |
                          {swap_handler,
                           Args1 :: term(),
                           NewState :: term(),
                           Handler2 :: atom() | {atom(), Id :: term()},
                           Args2 :: term()} |
                          remove_handler.

处理事件。

每当事件管理器收到使用 notify/2sync_notify/2 发送的事件时,将为每个已安装的事件处理程序调用此函数以处理该事件。

Eventnotify/2 / sync_notify/2Event 参数。

State 是事件处理程序的内部状态。

  • 如果返回 {ok, NewState}{ok, NewState, hibernate},则事件处理程序将保留在事件管理器中,并可能更新内部状态 NewState

  • 如果返回 {ok, NewState, hibernate},则事件管理器还会进入休眠状态(通过调用 proc_lib:hibernate/3),等待下一个事件发生。只要其中一个事件处理程序返回 {ok, NewState, hibernate},整个事件管理器进程就会休眠。

  • 如果返回 {swap_handler, Args1, NewState, Handler2, Args2},则通过先调用 Module:terminate(Args1, NewState),然后调用 Module2:init({Args2, Term}) 来用 Handler2 替换事件处理程序,其中 TermModule:terminate/2 的返回值。有关更多信息,请参阅 swap_handler/3

  • 如果返回 remove_handler,则通过调用 Module:terminate(remove_handler, State) 删除事件处理程序。

链接到此回调

handle_info(Info, State)

查看源码 (可选)
-callback handle_info(Info :: term(), State :: term()) ->
                         {ok, NewState :: term()} |
                         {ok, NewState :: term(), hibernate} |
                         {swap_handler,
                          Args1 :: term(),
                          NewState :: term(),
                          Handler2 :: atom() | {atom(), Id :: term()},
                          Args2 :: term()} |
                         remove_handler.

处理信息消息(常规进程消息)。

当事件管理器收到除事件或同步请求(或系统消息)之外的任何其他消息时,将为每个已安装的事件处理程序调用此函数。

Info 是收到的消息。

特别是,当进程在调用 add_sup_handler/3 后终止时,将进行此回调。附加到事件管理器的任何事件处理程序,该事件管理器又具有受监督的处理程序,都应预期 Module:handle_info({'EXIT', Pid, Reason}, State) 形状的回调。

有关 State 和可能的返回值的说明,请参阅 Module:handle_event/2

注意

此回调是可选的,因此回调模块不必导出它。gen_event 模块提供了此函数的默认实现,该实现会记录有关意外的 Info 消息,丢弃它并返回 {ok, State}

-callback init(InitArgs :: term()) ->
                  {ok, State :: term()} | {ok, State :: term(), hibernate} | {error, Reason :: term()}.

初始化事件处理程序。

每当向事件管理器添加新的事件处理程序时,都会调用此函数来初始化事件处理程序。

如果由于调用 add_handler/3add_sup_handler/3 而添加了事件处理程序,则 InitArgs 是这些函数的 Args 参数。

如果由于调用 swap_handler/3swap_sup_handler/3,或者由于其他回调函数之一返回了 swap 元组而替换了另一个事件处理程序,则 InitArgs 是一个元组 {Args, Term},其中 Args 是函数调用/返回元组中提供的参数,Term 是终止旧事件处理程序的结果,请参阅 swap_handler/3

如果成功,该函数将返回 {ok, State}{ok, State, hibernate},其中 State 是事件处理程序的初始内部状态。

如果返回 {ok, State, hibernate},则事件管理器将进入休眠状态(通过调用 proc_lib:hibernate/3),等待下一个事件发生。

链接到此回调

terminate(Args, State)

查看源代码 (可选)
-callback terminate(Args ::
                        term() |
                        {stop, Reason :: term()} |
                        stop | remove_handler |
                        {error, {'EXIT', Reason :: term()}} |
                        {error, term()},
                    State :: term()) ->
                       term().

处理事件处理程序终止。

每当从事件管理器中删除事件处理程序时,都会调用此函数。它与 Module:init/1 相反,并执行任何必要的清理工作。

如果由于调用 delete_handler/3swap_handler/3swap_sup_handler/3 而删除了事件处理程序,则 Arg 是此函数调用的 Args 参数。

如果事件处理程序与已终止且原因为 Reason 的进程具有受监管的连接,则 Arg = {stop, Reason}

如果由于事件管理器正在终止而删除了事件处理程序,则 Arg = stop

如果事件管理器是监督树的一部分,并且其主管命令其终止,则事件管理器将终止。即使它 *不是* 监督树的一部分,如果它从其父进程收到 'EXIT' 消息,它也会终止。

如果由于另一个回调函数返回了 remove_handler{remove_handler, Reply} 而删除了事件处理程序,则 Arg = remove_handler

如果由于回调函数返回了意外的值 Term 而删除了事件处理程序,则 Arg = {error, Term};如果回调函数失败,则 Arg = {error, {'EXIT', Reason}}

State 是事件处理程序的内部状态。

该函数可以返回任何项。如果由于调用 gen_event:delete_handler/3 而删除了事件处理程序,则该函数的返回值将成为此函数的返回值。如果要通过交换替换事件处理程序,则返回值将传递给新事件处理程序的 init 函数。否则,返回值将被忽略。

注意

此回调是可选的,因此回调模块不必导出它。gen_event 模块提供了没有清理的默认实现。

函数

链接到此函数

add_handler(EventMgrRef, Handler, Args)

查看源代码
-spec add_handler(EventMgrRef :: emgr_ref(), Handler :: handler(), Args :: term()) -> term().

向事件管理器添加新的事件处理程序。

新的事件处理程序将添加到事件管理器 EventMgrRef。事件管理器调用 Module:init/1 来初始化事件处理程序及其内部状态。

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)

查看源代码
-spec add_sup_handler(EventMgrRef :: emgr_ref(), Handler :: handler(), Args :: term()) -> term().

向事件管理器添加新的事件处理程序,并进行监督。

新的事件处理程序将按照 add_handler/3 的方式添加,但是事件管理器还会通过链接事件处理程序和调用进程来监督连接。

  • 如果调用进程稍后因 Reason 而终止,则事件管理器会通过调用 Module:terminate/2 来删除任何受监管的事件处理程序,然后为每个剩余的处理程序调用 Module:handle_info/2

  • 如果稍后删除事件处理程序,则事件管理器会向调用进程发送消息 {gen_event_EXIT,Handler,Reason}Reason 是以下之一

    • normal,如果事件处理程序由于调用 delete_handler/3 而被删除,或者回调函数返回了 remove_handler (请参阅下文)。
    • shutdown,如果事件处理程序由于事件管理器正在终止而被删除。
    • {swapped, NewHandler, Pid},如果进程 Pid 通过调用 swap_handler/3swap_sup_handler/3 将事件处理程序替换为另一个事件处理程序 NewHandler
    • 其他 term/0,如果事件处理程序由于错误而被删除。哪个项取决于错误。

有关参数和返回值的说明,请参阅 add_handler/3

链接到此函数

call(EventMgrRef, Handler, Request)

查看源代码
-spec call(EventMgrRef :: emgr_ref(), Handler :: handler(), Request :: term()) -> term().

等效于 call(EventMgrRef, Handler, Request, 5000)

链接到此函数

call(EventMgrRef, Handler, Request, Timeout)

查看源代码
-spec call(EventMgrRef :: emgr_ref(), Handler :: handler(), Request :: term(), Timeout :: timeout()) ->
              term().

对事件处理程序进行同步调用。

通过发送请求并等待直到收到答复或发生超时,将调用发送到安装在事件管理器 EventMgrRef 中的 Handler。事件管理器调用 Module:handle_call/2 来处理请求。

Request 是作为参数之一传递给 Module:handle_call/2 的任何项。

Timeout 是一个大于零的整数,它指定等待答复的毫秒数,或者原子 infinity 表示无限期等待。默认为 5000。如果在指定的时间内未收到答复,则函数调用失败。

返回值 ReplyModule:handle_call/2 的返回值中定义。如果未安装指定的事件处理程序,则函数返回 {error, bad_module}。如果回调函数失败并返回 Reason 或返回意外的值 Term,则此函数将分别返回 {error, {'EXIT', Reason}}{error, Term}

当此调用失败时,它会 退出 调用进程。退出项的形式为 {Reason, Location},其中 Location = {gen_event, call, ArgList}。请参阅 gen_server:call/3,其中描述了退出项中 Reason 的相关值。

链接到此函数

check_response(Msg, ReqId)

查看源代码 (自 OTP 23.0 起)
-spec check_response(Msg, ReqId) -> Result
                        when
                            Msg :: term(),
                            ReqId :: request_id(),
                            Response ::
                                {reply, Reply :: term()} | {error, {Reason :: term(), emgr_ref()}},
                            Result :: Response | no_reply.

检查接收到的消息是否为请求响应。

检查 Msg 是否是与请求标识符 ReqId 相对应的响应。请求必须由 send_request/3 发出,并且由调用此函数的同一进程发出。

如果 Msg 是与 ReqId 相对应的响应,则该响应将返回到 Reply 中。否则,此函数将返回 no_reply,并且不进行清理。因此,必须重复调用此函数,直到返回响应为止。

如果未安装指定的事件处理程序,则函数返回 {error, bad_module}。如果回调函数失败并返回 Reason 或返回意外的值 Term,则此函数将分别返回 {error, {'EXIT', Reason}}{error, Term}。如果事件管理器在调用此函数之前已经死亡,即;Msg 报告服务器的死亡,则此函数将返回 {error,{Reason, EventMgrRef}},其中 Reason 是退出原因。

链接到此函数

check_response(Msg, ReqIdCollection, Delete)

查看源代码 (自 OTP 25.0 起)
-spec check_response(Msg, ReqIdCollection, Delete) -> Result
                        when
                            Msg :: term(),
                            ReqIdCollection :: request_id_collection(),
                            Delete :: boolean(),
                            Response ::
                                {reply, Reply :: term()} | {error, {Reason :: term(), emgr_ref()}},
                            Result ::
                                {Response,
                                 Label :: term(),
                                 NewReqIdCollection :: request_id_collection()} |
                                no_request | no_reply.

检查接收到的消息是否为集合中的请求响应。

检查 Msg 是否是与存储在 ReqIdCollection 中的请求标识符相对应的响应。ReqIdCollection 的所有请求标识符都必须与使用 send_request/3send_request/5 发出的请求相对应,并且所有请求都必须由调用此函数的进程发出。

响应中的 Label 是与响应对应的请求标识符关联的 Label。请求标识符的 Label将请求 id 存储在集合中时,或者在使用 send_request/5 发送请求时关联。

check_response/2 相比,与特定请求标识符关联的返回结果或异常将包装在 3 元组 {Response, Label, NewReqIdCollection} 中。Responsecheck_response/2 将会生成的值,Label 是与特定 请求标识符 关联的值,NewReqIdCollection 是可能修改过的请求标识符集合。

如果 ReqIdCollection 为空,则将返回 no_request

如果 MsgReqIdCollection 中的任何请求标识符都不对应,则返回 no_reply

如果 Deletetrue,则与 Label 的关联已从结果 NewReqIdCollection 中的 ReqIdCollection 中删除。如果 Deletefalse,则 NewReqIdCollection 将等于 ReqIdCollection。请注意,删除关联不是免费的,并且包含已处理请求的集合仍然可以被后续调用 check_response/3receive_response/3wait_response/3 使用。

但是,如果不删除已处理的关联,则上述调用将无法检测到何时没有更多未处理的请求需要处理,因此您必须通过其他方式来跟踪此情况,而不是依赖于 no_request 返回值。请注意,如果您将仅包含已处理或已放弃请求的关联的集合传递给 check_response/3,它将始终返回 no_reply

链接到此函数

delete_handler(EventMgrRef, Handler, Args)

查看源代码
-spec delete_handler(EventMgrRef :: emgr_ref(), Handler :: handler(), Args :: term()) -> term().

从事件管理器删除事件处理程序。

此函数从事件管理器 EventMgrRef 中删除事件处理程序 Handler。事件管理器调用 Module:terminate/2 来终止事件处理程序。

Args 是作为参数之一传递给 Module:terminate/2 的任何项。

返回值是 Module:terminate/2 的返回值。如果未安装指定的事件处理程序,则该函数返回 {error, module_not_found}。如果回调函数失败并返回 Reason,则该函数返回 {'EXIT', Reason}

链接到此函数

notify(EventMgrRef, Event)

查看源代码
-spec notify(EventMgrRef :: emgr_ref(), Event :: term()) -> ok.

向事件管理器发送异步事件通知。

事件被发送到 EventMgrRef,它调用 Module:handle_event/2,为每个已安装的事件处理程序处理事件。

Event 是作为参数之一传递给 Module:handle_event/2 的任何项。

即使指定的事件管理器不存在,notify/1 也不会失败,除非它被指定为 Name

链接到此函数

receive_response(ReqId, Timeout)

查看源代码 (自 OTP 24.0 起)
-spec receive_response(ReqId, Timeout) -> Result
                          when
                              ReqId :: request_id(),
                              Timeout :: response_timeout(),
                              Response ::
                                  {reply, Reply :: term()} | {error, {Reason :: term(), emgr_ref()}},
                              Result :: Response | timeout.

接收请求响应。

接收与请求标识符 ReqId 对应的响应。该请求必须由 send_request/3 发出,并且必须由调用此函数的同一进程发出。

Timeout 指定等待响应的时间。如果在指定的时间内未收到响应,则此函数返回 timeout。假设服务器在支持别名(在 OTP 24 中引入)的节点上执行,则请求也将被放弃。也就是说,超时后将不会收到任何响应。否则,可能会在稍后收到错误的响应。

返回值 ReplyModule:handle_call/2 的返回值中定义。

如果未安装指定的事件处理程序,则此函数返回 {error, bad_module}。如果回调函数失败并返回 Reason 或返回意外值 Term,则此函数分别返回 {error, {'EXIT', Reason}}{error,Term}。如果事件管理器在请求之前或期间死亡,则此函数返回 {error, {Reason, EventMgrRef}}

wait_response/2receive_response/2 之间的区别在于,receive_response/2 在超时时放弃请求,以便忽略潜在的未来响应,而 wait_response/2 则不会。

链接到此函数

receive_response(ReqIdCollection, Timeout, Delete)

查看源代码 (自 OTP 25.0 起)
-spec receive_response(ReqIdCollection, Timeout, Delete) -> Result
                          when
                              ReqIdCollection :: request_id_collection(),
                              Timeout :: response_timeout(),
                              Delete :: boolean(),
                              Response ::
                                  {reply, Reply :: term()} | {error, {Reason :: term(), emgr_ref()}},
                              Result ::
                                  {Response,
                                   Label :: term(),
                                   NewReqIdCollection :: request_id_collection()} |
                                  no_request | timeout.

接收集合中的请求响应。

ReqIdCollection 中接收响应。ReqIdCollection 的所有请求标识符必须对应于使用 send_request/3send_request/5 发出的请求,并且所有请求必须由调用此函数的进程发出。

响应中的 Label 是与响应对应的请求标识符关联的 Label。请求标识符的 Label 在将请求 ID 添加到集合时,或者在使用 send_request/5 发送请求时关联。

receive_response/2 相比,与特定请求标识符关联的返回结果或异常将包装在一个 3 元组 {Response, Label, NewReqIdCollection} 中。Responsereceive_response/2 将产生的值,Label 是与特定 请求标识符 关联的值,NewReqIdCollection 是一个可能修改过的请求标识符集合。

如果 ReqIdCollection 为空,则将返回 no_request

Timeout 指定等待响应的时间。如果在指定的时间内未收到响应,则该函数返回 timeout。假设服务器在支持别名(在 OTP 24 中引入)的节点上执行,则 ReqIdCollection 标识的所有请求也将被放弃。也就是说,超时后将不会收到任何响应。否则,可能会在稍后收到错误的响应。

receive_response/3wait_response/3 之间的区别在于,receive_response/3 在超时时放弃请求,以便忽略潜在的未来响应,而 wait_response/3 则不会。

如果 Deletetrue,则与 Label 的关联将从结果 NewReqIdCollection 中的 ReqIdCollection 中删除。如果 Deletefalse,则 NewReqIdCollection 将等于 ReqIdCollection。请注意,删除关联不是免费的,并且包含已处理请求的集合仍然可以被后续调用 receive_response/3check_response/3wait_response/3 使用。

但是,如果不删除已处理的关联,则上述调用将无法检测到何时没有更多未处理的请求需要处理,因此您必须通过其他方式来跟踪此情况,而不是依赖于 no_request 返回值。请注意,如果您将仅包含已处理或已放弃请求的关联的集合传递给 receive_response/3,它将始终阻塞,直到 Timeout 过期,然后返回 timeout

链接到此函数

reqids_add(ReqId, Label, ReqIdCollection)

查看源代码 (自 OTP 25.0 起)
-spec reqids_add(ReqId :: request_id(), Label :: term(), ReqIdCollection :: request_id_collection()) ->
                    NewReqIdCollection :: request_id_collection().

将请求标识符存储在集合中。

存储 ReqId 并通过将此信息添加到 ReqIdCollection 并返回结果请求标识符集合,将 Label 与请求标识符关联。

链接到此函数

reqids_new()

查看源代码 (自 OTP 25.0 起)
-spec reqids_new() -> NewReqIdCollection :: request_id_collection().

创建空的请求标识符集合。

返回一个新的空请求标识符集合。可以使用请求标识符集合来处理多个未完成的请求。

通过 send_request/3 发出的请求的请求标识符可以使用 reqids_add/3 保存在请求标识符集合中。稍后可以使用此类请求标识符集合,通过将集合作为参数传递给 receive_response/3wait_response/3check_response/3,以获取集合中与请求对应的单个响应。

reqids_size/1 可用于确定集合中请求标识符的数量。

链接到此函数

reqids_size(ReqIdCollection)

查看源代码 (自 OTP 25.0 起)
-spec reqids_size(ReqIdCollection :: request_id_collection()) -> non_neg_integer().

返回 ReqIdCollection 中的请求标识符的数量。

链接到此函数

reqids_to_list(ReqIdCollection)

查看源代码 (自 OTP 25.0 起)
-spec reqids_to_list(ReqIdCollection :: request_id_collection()) ->
                        [{ReqId :: request_id(), Label :: term()}].

将请求标识符集合转换为列表。

返回 {ReqId, Label} 元组的列表,该列表对应于 ReqIdCollection 中所有带有其关联标签的请求标识符。

链接到此函数

send_request(EventMgrRef, Handler, Request)

查看源代码 (自 OTP 23.0 起)
-spec send_request(EventMgrRef :: emgr_ref(), Handler :: handler(), Request :: term()) ->
                      ReqId :: request_id().

向事件处理程序发送异步 call 请求。

此函数将调用请求 Request 发送到由 EventMgrRef 标识的事件管理器中安装的事件处理程序 Handler,并返回请求标识符 ReqId。返回值 ReqId 稍后应与 receive_response/2wait_response/2check_response/2 一起使用,以获取请求的实际结果。

除了将请求标识符直接传递给这些函数之外,还可以使用 reqids_add/3 将其存储在请求标识符集合中。稍后可以使用此类请求标识符集合,通过将集合作为参数传递给 receive_response/3wait_response/3check_response/3,以获取集合中与请求对应的单个响应。如果要将请求标识符存储在集合中,您可能需要考虑使用 send_request/5

调用 gen_event:receive_response(gen_event:send_request(EventMgrRef, Handler, Request), Timeout) 可以被视为等同于 gen_event:call(EventMgrRef, Handler, Request, Timeout),忽略错误处理。

事件管理器调用 Module:handle_call/2 来处理请求。

Request 可以是任何项,并作为参数之一传递给 Module:handle_call/2

链接到此函数

send_request(EventMgrRef, Handler, Request, Label, ReqIdCollection)

查看源代码 (自 OTP 25.0 起)
-spec send_request(EventMgrRef :: emgr_ref(),
                   Handler :: handler(),
                   Request :: term(),
                   Label :: term(),
                   ReqIdCollection :: request_id_collection()) ->
                      NewReqIdCollection :: request_id_collection().

向事件处理程序发送异步 call 请求,并将其存储在请求标识符集合中。

此函数将调用请求 Request 发送到由 EventMgrRef 标识的事件管理器中安装的事件处理程序 HandlerLabel 将与操作的请求标识符关联,并添加到返回的请求标识符集合 NewReqIdCollection 中。

该集合稍后可用于通过将集合作为参数传递给 receive_response/3wait_response/3check_response/3 来获取集合中与请求对应的单个响应。

与调用 gen_event:reqids_add(gen_event:send_request(EventMgrRef, Handler, Request), Label, ReqIdCollection) 相同,但效率略高。

-spec start() -> start_ret().

等效于 start([])

-spec start(EventMgrName :: emgr_name()) -> start_ret();
           (Options :: options()) -> start_ret().

创建独立的事件管理器进程,可能无名。

等效于 start(EventMgrName, Options)

使用参数 EventMgrNameOptions[]

使用参数 Options 创建一个无名的事件管理器。

有关参数和返回值的说明,请参阅 start_link/2

链接到此函数

start(EventMgrName, Options)

查看源代码 (自 OTP 20.0 起)
-spec start(EventMgrName :: emgr_name(), Options :: options()) -> start_ret().

创建独立的事件管理器进程。

创建的事件管理器进程不属于监督树的一部分,因此没有主管。

有关参数和返回值的说明,请参阅 start_link/2

-spec start_link() -> start_ret().

等效于 start_link([])

-spec start_link(EventMgrName :: emgr_name()) -> start_ret();
                (Options :: options()) -> start_ret().

创建事件管理器进程作为监督树的一部分,可能无名。

等效于 start_link(EventMgrName, Options)

使用参数 EventMgrNameOptions[]

使用参数 Options 创建一个无名的事件管理器。

有关参数和返回值的说明,请参阅 start_link/2

链接到此函数

start_link(EventMgrName, Options)

查看源代码 (自 OTP 20.0 起)
-spec start_link(EventMgrName :: emgr_name(), Options :: options()) -> start_ret().

创建事件管理器进程作为监督树的一部分。

该函数应由主管直接或间接调用。例如,它确保事件管理器链接到调用者(主管)。

  • 如果存在选项 {hibernate_after, HibernateAfterTimeout},则 gen_event 进程会等待任何消息 HibernateAfterTimeout 毫秒,如果没有收到消息,则该进程会自动进入休眠状态(通过调用 proc_lib:hibernate/3)。

如果事件管理器成功创建,该函数将返回 {ok, Pid},其中 Pid 是事件管理器的 pid/0

如果已存在具有指定 EventMgrName 的进程,该函数将返回 {error,{already_started,OtherPid}},其中 OtherPid 是该进程的 pid,并且事件管理器进程将以 normal 为原因退出。

如果事件管理器在指定的启动超时 {timeout, Time} 内未能启动,这种情况极不可能发生,因为启动不会与其他进程交互,则该函数将返回 {error, timeout},并且失败的事件管理器将以 exit(_, kill) 被终止。

如果 start_link/1,2 返回 {error, _},则启动的事件管理器进程已终止。如果 'EXIT' 消息已传递给调用进程(由于进程链接),则该消息已被使用。

警告

在 OTP 26.0 之前,如果启动的事件管理器未能注册其名称,则此函数可能会在启动的事件管理器进程终止之前返回 {error, {already_started, OtherPid}},因此再次启动可能会失败,因为注册的名称尚未注销,并且稍后可能会向调用此函数的进程发送 'EXIT' 消息。

但是,如果启动超时,此函数会终止启动的事件管理器进程并返回 {error, timeout},然后进程链接 {'EXIT', Pid, killed} 消息使用。

启动在 OTP 26.0 中是同步进行的,并且保证了来自失败启动的任何进程链接 'EXIT' 消息都不会在调用者的收件箱中停留。

链接到此函数

start_monitor()

查看源代码 (自 OTP 23.0 起)
-spec start_monitor() -> start_mon_ret().

等效于 start_monitor([])

链接到此函数

start_monitor(EventMgrNameOrOptions)

查看源代码 (自 OTP 23.0 起)
-spec start_monitor(EventMgrNameOrOptions :: emgr_name() | options()) -> start_mon_ret().

创建独立的事件管理器进程,受到监控,可能无名。

等效于 start_monitor(EventMgrName, Options)

使用参数 EventMgrNameOptions[]

使用参数 Options 创建一个无名的事件管理器。

有关参数和返回值的说明,请参阅 start_monitor/2start_link/1

链接到此函数

start_monitor(EventMgtName, Options)

查看源代码 (自 OTP 23.0 起)
-spec start_monitor(EventMgtName :: emgr_name(), Options :: options()) -> start_mon_ret().

创建独立的事件管理器进程,受到监控。

创建的事件管理器进程不属于监督树的一部分,因此没有主管。原子地为新创建的进程设置一个监视器。

有关参数和返回值的说明,请参阅 start_link/2。请注意,成功启动的返回值与 start_link/2 不同。start_monitor/0,1,2 将返回 {ok, {Pid, Mon}},其中 Pid 是进程的进程标识符,而 Mon 是设置为监视进程的监视器的引用。如果启动不成功,则调用者将被阻塞,直到收到 DOWN 消息并从消息队列中删除。

-spec stop(EventMgrRef :: emgr_ref()) -> ok.

等效于 stop(EventMgrRef, normal, infinity)

链接到此函数

stop(EventMgrRef, Reason, Timeout)

查看源代码 (自 OTP 18.0 起)
-spec stop(EventMgrRef :: emgr_ref(), Reason :: term(), Timeout :: timeout()) -> ok.

停止事件管理器。

命令事件管理器 EventMgrRef 以指定的 Reason 退出,并等待其终止。在终止之前,gen_event 会为每个已安装的事件处理程序调用 Module:terminate(stop,...)

如果事件管理器以预期原因终止,则该函数返回 ok。除 normalshutdown{shutdown, Term} 之外的任何其他原因都会使用 logger 发出错误报告。

Timeout 是一个大于零的整数,用于指定等待事件管理器终止的毫秒数,或原子 infinity 以无限期等待。如果事件管理器在指定的时间内未终止,则调用将以 timeout 为原因退出调用进程。

如果进程不存在,则调用将以 noproc 为原因退出调用进程,如果与服务器运行的远程 Node 的连接失败,则以 {nodedown, Node} 为原因退出。

链接到此函数

swap_handler(EventMgrRef, OldHandler, NewHandler)

查看源代码
-spec swap_handler(EventMgrRef :: emgr_ref(),
                   OldHandler :: {handler(), term()},
                   NewHandler :: {handler(), term()}) ->
                      ok | {error, term()}.

替换事件处理程序。

此函数替换事件管理器 EventMgrRef 中的事件处理程序。

有关 OldHandlerNewHandler 的说明,请参阅 add_handler/3

首先删除旧的事件处理程序 OldHandler。事件管理器调用 OldModule:terminate(Args1, ...),其中 OldModuleOldHandler 的回调模块,并收集返回值。

然后添加新的事件处理程序 NewHandler,并通过调用 NewModule:init({Args2,Term}) 初始化,其中 NewModuleNewHandler 的回调模块,TermOldModule:terminate/2 的返回值。这使得可以从 OldHandlerNewHandler 传递信息。

即使未安装指定的旧事件处理程序(在这种情况下,Term = error),或者 OldModule:terminate/2Reason 失败(在这种情况下,Term = {'EXIT', Reason}),也会添加新的处理程序。即使 NewModule:init/1 失败,也会删除旧的处理程序。

如果在 OldHandler 和进程 Pid 之间存在受监督的连接,则在 NewHandlerPid 之间存在一个受监督的连接。

如果 NewModule:init/1 返回正确的值,则此函数将返回 ok。如果 NewModule:init/1Reason 失败或返回意外的值 Term,则此函数将分别返回 {error, {'EXIT', Reason}}{error, Term}

链接到此函数

swap_sup_handler(EventMgrRef, OldHandler, NewHandler)

查看源代码
-spec swap_sup_handler(EventMgrRef :: emgr_ref(),
                       OldHandler :: {handler(), term()},
                       NewHandler :: {handler(), term()}) ->
                          ok | {error, term()}.

替换事件处理程序,并进行监督。

以与 swap_handler/3 相同的方式替换事件管理器 EventMgrRef 中的事件处理程序,但也监督 NewHandler 和调用进程之间的连接。

有关参数和返回值的说明,请参阅 swap_handler/3

链接到此函数

sync_notify(EventMgrRef, Event)

查看源代码
-spec sync_notify(EventMgrRef :: emgr_ref(), Event :: term()) -> ok.

向事件管理器发送同步事件通知。

事件被发送到 EventMgrRef,该管理器为每个已安装的事件处理程序调用 Module:handle_event/2 来处理事件。在所有事件处理程序处理完事件后,此函数将返回 ok

Event 是作为参数之一传递给 Module:handle_event/2 的任何项。

链接到此函数

wait_response(ReqId, WaitTime)

查看源代码 (自 OTP 23.0 起)
-spec wait_response(ReqId, WaitTime) -> Result
                       when
                           ReqId :: request_id(),
                           WaitTime :: response_timeout(),
                           Response ::
                               {reply, Reply :: term()} | {error, {Reason :: term(), emgr_ref()}},
                           Result :: Response | timeout.

等待请求响应。

等待请求标识符 ReqId 的响应。请求必须由调用 send_request/3 的同一进程通过 send_request/3 发出。

WaitTime 指定等待响应的时间。如果在指定的时间内未收到响应,则该函数将返回 timeout 且不执行清理。因此,可以重复调用该函数,直到返回响应。

返回值 ReplyModule:handle_call/2 的返回值中定义。

如果未安装指定的事件处理程序,则该函数将返回 {error, bad_module}。如果回调函数因 Reason 失败或返回意外值 Term,则此函数将分别返回 {error,{'EXIT',Reason}}{error,Term}。如果事件管理器在请求之前或期间终止,则此函数将返回 {error, {Reason, EventMgrRef}}

receive_response/2wait_response/2 之间的区别在于,receive_response/2 会在超时时放弃请求,以便忽略潜在的未来响应,而 wait_response/2 不会。

链接到此函数

wait_response(ReqIdCollection, WaitTime, Delete)

查看源代码 (自 OTP 25.0 起)
-spec wait_response(ReqIdCollection, WaitTime, Delete) -> Result
                       when
                           ReqIdCollection :: request_id_collection(),
                           WaitTime :: response_timeout(),
                           Delete :: boolean(),
                           Response ::
                               {reply, Reply :: term()} | {error, {Reason :: term(), emgr_ref()}},
                           Result ::
                               {Response,
                                Label :: term(),
                                NewReqIdCollection :: request_id_collection()} |
                               no_request | timeout.

等待集合中的任何请求响应。

等待 ReqIdCollection 中的响应。ReqIdCollection 的所有请求标识符都必须对应于使用 send_request/3send_request/5 发出的请求,并且所有请求都必须由调用此函数的进程发出。

响应中的 Label 是与响应对应的请求标识符关联的 Label。请求标识符的 Label 在将请求 ID 添加到集合时,或者在使用 send_request/5 发送请求时关联。

wait_response/2 相比,与特定请求标识符关联的返回结果或异常将封装在 3 元组 {Response, Label, NewReqIdCollection} 中。Responsewait_response/2 将产生的值,Label 是与特定 请求标识符 关联的值,而 NewReqIdCollection 是可能修改过的请求标识符集合。

如果 ReqIdCollection 为空,则将返回 no_request

如果在 WaitTime 过期之前没有收到响应,则返回 timeout。在收到响应并通过 check_response()receive_response()wait_response() 完成响应之前,可以根据需要多次继续等待响应。

receive_response/3wait_response/3 之间的区别在于,receive_response/3 在超时时放弃请求,以便忽略潜在的未来响应,而 wait_response/3 则不会。

如果 Deletetrue,则与 Label 的关联已从结果 NewReqIdCollection 中的 ReqIdCollection 中删除。如果 Deletefalse,则 NewReqIdCollection 将等于 ReqIdCollection。请注意,删除关联并非免费操作,并且包含已处理请求的集合仍然可以被后续对 wait_response/3check_response/3receive_response/3 的调用使用。

但是,如果不删除已处理的关联,则上述调用将无法检测到何时没有更多未完成的请求需要处理,因此您必须以其他方式跟踪此情况,而不是依赖于 no_request 返回值。请注意,如果您将仅包含已处理或放弃请求的关联的集合传递给此函数,它将始终阻塞直到 WaitTime 过期,然后返回 timeout

链接到此函数

which_handlers(EventMgrRef)

查看源代码
-spec which_handlers(EventMgrRef :: emgr_ref()) -> [handler()].

返回事件管理器中的所有事件处理程序。

此函数返回事件管理器 EventMgrRef 中安装的所有事件处理程序的列表。

有关 Handler 的描述,请参见 add_handler/3