来源:http://www.cnblogs.com/puputu/articles/1689623.html

1. 事件处理规则

在OTP中,事件管理器是一个事件可以发送到的命名对象,一个事件可以是一个错误、一个警告、或者一些要写入日志的信息

在事件管理器中,有0个、一个或者多个事件处理器被安装,当事件管理器被一个事件通知时,这个事件将被安装在事件管理器中的事件处理器处理,

事件管理器用一个进程实现,事件处理器用回调模块实现。事件管理器本质上维护一个{Module, State}列表,每一个Module为一个事件处理器,而State为事件处理器的内部状态。

2. 例子

事件处理器的回调模块把错误信息写入终端

-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),
{ok, Fd}.
handle_event(ErrorMsg, Fd) ->
io:format(Fd, "***Error*** ~p~n", [ErrorMsg]),
{ok, Fd}.
terminate(_Args, Fd) ->
file:close(Fd).

3. 启动事件管理器

调用gen_event:start_link({local, error_man})

启动管理器,这个函数生成并连接到一个新进程,参数{local, error_man}指定名称,在这个例子中,事件管理器被局部注册为error_man

假如忽略名称,那么事件管理器不会被注册,它的PID将被使用。名称也可以是这种形式{global, Name},这样,事件管理器的名称是用global:register_name/2注册的。

假如事件管理器是监控树的一部分,那么gen_event:start_link必须被使用,也就是被监控树启动,而gen_event:start启动单独的事件管理器,也就是事件管理器不是监控树的一部分。

4. 添加事件处理器

下面的例子显示怎样启动一个事件管理器和添加一个事件处理器

1> gen_event:start({local, error_man}).
{ok,<0.31.0>}
2> gen_event:add_handler(error_man, terminal_logger, []).
ok

gen_event:add_handler(error_man, terminal_logger, [])为error_man添加处理器terminal_logger,事件管理器调用terminal_logger:init([])这个回调函数, []是参数,init要返回一个{ok, State},State是事件处理器的内部状态

init(_Args) ->
{ok, []}.

这里,init不需要任何输入参数,对于terminal_logger,也没使用内部状态,对于file_logger,内部状态保存了打开的文件描述符

init(File) ->
{ok, Fd} = file:open(File, read),
{ok, Fd}.

5. 关于事件通知

3> gen_event:notify(error_man, no_reply).
***Error*** no_reply
ok

error_man是事件管理器的名称,no_reply是事件,事件作为消息发送给事件管理器,当事件被收到时,事件管理器为每个安装的事件处理器按安 装次序调用handle_event(Event, State),这个函数期待返回{ok, State1},State1是事件处理器的新状态。

在terminal_logger中

handle_event(ErrorMsg, State) ->
io:format("***Error*** ~p~n", [ErrorMsg]),
{ok, State}.

在file_logger中

handle_event(ErrorMsg, Fd) ->
io:format(Fd, "***Error*** ~p~n", [ErrorMsg]),
{ok, Fd}.

6. 删除一个事件处理器

gen_event:delete_handler(error_man, terminal_logger, []),这个函数向事件管理器error_man发送了一个消息,告诉他删除terminal_logger这个事件处理器,事件管理器将调用 terminal_logger:terminate([], State),参数[]是delete_handler的第三个参数,terminate以init相反的方向调用,以完成清理工作,返回值被忽略。

在terminal_logger中,没有清理动作

terminate(_Args, _State) ->
ok.

在file_logger中,文件描述符被关掉

terminate(_Args, Fd) ->
file:close(Fd).

7. 停止

当事件管理器被停止,它给每个注册的事件处理器调用terminate/2的机会,就好像事件处理器被删除一样。如果事件管理器是监控树的一部分,不需要显示的停止事件管理器。当事件管理器作为单独进程使用时,则调用gen_event:stop(error_man).

erlang四大behaviour之三-gen_event的更多相关文章

  1. erlang四大behaviour之四-supervisor

    http://www.cnblogs.com/puputu/articles/1689621.html 1. 监督规则 一个监督者负责启动.停止.监控他的子进程.监督者的一个基本概念就是当必要的时候重 ...

  2. erlang四大behaviour之二-gen_fsm

    来源:http://www.cnblogs.com/puputu/articles/1701012.html 今天介绍erlang的一个非常重要的behaviour,就是gen_fsm-有限状态机,有 ...

  3. erlang四大behaviour之一gen_server

      来源:http://www.cnblogs.com/puputu/articles/1701017.html erlang程序设计里面有个设计原则就是把你的进程构造成树,把共用代码提出来,特定功能 ...

  4. erlang四大behaviour之一gen_server(转载)

    erlang程序设计里面有个设计原则就是把你的进程构造成树,把共用代码提出来,特定功能用自己的module实现,这也就是behaviour了,应用behaviour可以减少与本身事务无关的代码量,设计 ...

  5. Android 四大组件之三(广播)

    1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器).广播作为Android组件间的通 ...

  6. 8、四大组件之三-ContentProvider

    课程目标: 理解ContentProvider的作用及好处 认清ContentProvider与数据存储的关系 掌握ContentProvider对外提供的数据模型形式 能够编写ContentReso ...

  7. VFS四大对象之三 struct dentry

    继上一篇文章介绍了inode结构体:继续介绍目录项dentry: http://www.cnblogs.com/linhaostudy/p/7427794.html 三.dentry结构体 目录项:目 ...

  8. 【转】Excel-VBA操作文件四大方法之三

    三.利用FileSystemObject对象来处理文件 FileSystemObject对象模型,是微软提供的专门用来访问计算机文件系统的,具有大量的属性.方法和事件.其使用面向对象的“object. ...

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

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

随机推荐

  1. python1 tkinter

    turtle 图形: turtle.color(c) 设置笔的颜色turtle.fillcolor(c) 设置笔填充颜色turtle.begin_fill()   在填充颜色前访问这个方法turtle ...

  2. bzDemo

    <Public> <property name="Types"> <get/> </property> <method nam ...

  3. SAP HANA 能做什么

    HANA不是一个数据仓库,而是一个平台,在这个平台之上用户可以构建数据仓库或集市.报表和仪表盘等. HANA能做的,首先是作为内存数据库,提供数据插入.修改和高效的查询功能. 其次,作为一个平台,在H ...

  4. iOS UIBezierPath类 介绍

      使用UIBezierPath类可以创建基于矢量的路径,这个类在UIKit中.此类是Core Graphics框架关于path的一个封装.使用此类可以定义简单的形状,如椭圆或者矩形,或者有多个直线和 ...

  5. linux ll命令参数的详解

    用法:ls [选项]... [文件]... 列出 FILE 的信息(默认为当前目录). 如果不指定-cftuvSUX 或--sort 选项,则根据字母大小排序. 长选项必须使用的参数对于短选项时也是必 ...

  6. 三大框架之hibernate的反转

    选择工程.包名 Finish

  7. linux重要目录说明

    1 home :root用户的home 目录是root,普通用户的home 目录是/home,users/(不要随便使用root权限,小白容易改错东西哒) 2 bin:常用可执行文件:/bin./us ...

  8. HTTP状态码含义

    本文内容是在有道云笔记中找到的,已不知复制自何处,抱歉 一些常见的状态代码为:200 - 服务器成功返回网页 404 - 请求的网页不存在 503 - 服务器暂时不可用   1xx(临时响应) 用于表 ...

  9. APK安装时的过滤方式:包名白名单、证书认证

    1.定义一些全局变量,文件位置: Build.java (frameworks\base\core\java\android\os) /** * 包管理方式名称<br> * whiteli ...

  10. (转载)uefi启动解析:由原理到实例

    这是本文的全部内容:A:什么是UEFI,其含义B:UEFI模块包含的文件逐个分析及其引导流程+ESP分区的本质C:判断自己的机器是X64(64 bit)构架还是IA32(32 bit)的构架D:给传统 ...