zoukankan      html  css  js  c++  java
  • 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({localerror_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).

  • 相关阅读:
    JavaScript获取查询字符串
    Struts2 验证码图片实例
    js函数重载
    js面向对象基础
    js上下文
    java克隆入门和深入
    js类型检查
    js闭包
    Phonegap移动开发:布局总结(一) 全局
    Python发送多附件邮件的方法
  • 原文地址:https://www.cnblogs.com/yanwei-wang/p/4469112.html
Copyright © 2011-2022 走看看