Erlang -- gen_event

博客介绍了gen_event行为模块的事件处理功能,它由事件管理器和多个事件处理程序构成。事件管理器有标准接口函数,事件处理程序为回调模块。还说明了事件管理器的创建、终止、添加和删除事件处理器等操作,最后给出了相关例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

### Erlang OTP 的概念 Erlang OTP (Open Telecom Platform) 是一套用于构建高可用性和分布式系统的中间件、工具和设计原则集合。OTP 不仅是一组库,还是一种架构风格,旨在充分利用 Erlang 编程语言的并发处理能力来应对复杂的大规模通信系统设计挑战[^1]。 #### 关键特性 OTP 提供了一系列预定义的行为模式(behaviours),如 `gen_server`、`gen_fsm` 和 `gen_event` 等,允许开发者基于这些行为创建自定义进程模型,确保遵循统一的设计模式并实施最佳实践[^3]。通过这种方式,开发人员能够更容易地编写健壮的应用程序和服务,同时减少重复劳动,提高生产率。 此外,OTP 还包含了监督树(supervision tree)、应用程序管理等功能模块,进一步增强了系统的稳定性和可维护性。监督树机制使得即使某个子系统发生崩溃也能自动重启恢复正常运行状态;而应用程序管理则提供了启动、停止整个软件包的支持。 对于初学者来说,可以通过阅读官方文档中的相关内容加深理解,并尝试动手实现简单的 Gen_Server 应用来熟悉 OTP 框架的实际操作流程[^2]。 ```erlang -module(hello_world). -behaviour(gen_server). %% API functions -export([start_link/0]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -record(state, {}). %%%=================================================================== %%% API functions %%%=================================================================== start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). %%%=================================================================== %%% gen_server callbacks %%%=================================================================== init([]) -> {ok, #state{}}. handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. handle_cast(_Msg, State) -> {noreply, State}. handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. ``` 此代码片段展示了如何定义一个最基础版本的 Gen_Server 实现——它实现了必要的回调函数接口,但并未加入任何具体业务逻辑。这有助于新手快速掌握 OTP 中最基本的服务器组件结构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值