erlang四大behaviour之三-gen_event
来源: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的更多相关文章
- erlang四大behaviour之四-supervisor
http://www.cnblogs.com/puputu/articles/1689621.html 1. 监督规则 一个监督者负责启动.停止.监控他的子进程.监督者的一个基本概念就是当必要的时候重 ...
- erlang四大behaviour之二-gen_fsm
来源:http://www.cnblogs.com/puputu/articles/1701012.html 今天介绍erlang的一个非常重要的behaviour,就是gen_fsm-有限状态机,有 ...
- erlang四大behaviour之一gen_server
来源:http://www.cnblogs.com/puputu/articles/1701017.html erlang程序设计里面有个设计原则就是把你的进程构造成树,把共用代码提出来,特定功能 ...
- erlang四大behaviour之一gen_server(转载)
erlang程序设计里面有个设计原则就是把你的进程构造成树,把共用代码提出来,特定功能用自己的module实现,这也就是behaviour了,应用behaviour可以减少与本身事务无关的代码量,设计 ...
- Android 四大组件之三(广播)
1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器).广播作为Android组件间的通 ...
- 8、四大组件之三-ContentProvider
课程目标: 理解ContentProvider的作用及好处 认清ContentProvider与数据存储的关系 掌握ContentProvider对外提供的数据模型形式 能够编写ContentReso ...
- VFS四大对象之三 struct dentry
继上一篇文章介绍了inode结构体:继续介绍目录项dentry: http://www.cnblogs.com/linhaostudy/p/7427794.html 三.dentry结构体 目录项:目 ...
- 【转】Excel-VBA操作文件四大方法之三
三.利用FileSystemObject对象来处理文件 FileSystemObject对象模型,是微软提供的专门用来访问计算机文件系统的,具有大量的属性.方法和事件.其使用面向对象的“object. ...
- Erlang/OTP设计原则(文档翻译)
http://erlang.org/doc/design_principles/des_princ.html 图和代码皆源自以上链接中Erlang官方文档,翻译时的版本为20.1. 这个设计原则,其实 ...
随机推荐
- CSS继承性+层叠性+盒子+浮动
CSS继承性+层叠性+盒子+浮动 CSS继承性 <style> div{ color: pink; font-siz ...
- Angular2 + NativeScript 跨平台开发笔记(一)
NativeScript 是一款跟 ReactNative 对着怼的移动开发技术,其官方钦定了 Angular2 作为推荐的技术框架,那么如何让在浏览器中运行的 Angular2 Web app 项目 ...
- R安装
linux: 在编译R之前,需要通过yum安装以下几个程序: #yum install gcc-gfortran #否则报”configure: error: No F77 ...
- [M]带属性块参照的转换
有一张表格,表格的每一行都由带有属性的块参照组成,如图: 魔法表格不能直接识别有块参照组成的表格,需要使用 EXPLODE 命令将块参照分解,但多分解带有属性的块只能得到属性的定义 这是就需要使用 B ...
- 用CKEDITOR 做自助上传的解决方案2
1,在plugins下新建文件夹 multiimg 2,创建文件plugin.js (function() { CKEDITOR.plugins.add("multiimg", { ...
- AppDelegate 里一个基本的跳转方法,用来在rootView崩溃的时候直接调试我自己的页面
将 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)lau ...
- 在spring拦截器中response输出html标签到页面
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object ...
- 关于jq的load不用回调获取其中dom元素方法
jq的load方法如果要操作其中的dom元素,需要使用回调,等其加载完了再进行dom元素的获取,今天看我们项目组长写的一段代码,发现不用回调也能获取到其中的元素. 具体是这样写的: <scrip ...
- SPA 单页面应用
SPA一般只一个web页面,通过ajax,router等技术实现局部刷新,不会随着用户操作而出现重新加载页面或者页面跳转的功能,所有的用户操作都在一个页面实现. 组件化:UI组件和非UI组件 传统的u ...
- zstu 4214 高楼扔鸡蛋(google 面试题)dp
input T 1<=T<=10000 n m 1<=n<=2000000007 1<=m<=32 output m个鸡蛋从1到n哪一楼x扔下去刚好没碎,而再x+1 ...