Erlang事件处理器gen_event

本文介绍了Erlang的gen_event模块,它是一个事件管理器进程,允许动态添加和删除事件处理器。gen_event不同于gen_server,它将回调函数划分为多个事件处理器模块。文中讲解了如何使用gen_event,包括编写事件处理器、创建和添加处理器,以及事件通知的过程,并通过源码分析了添加处理器和处理事件的具体步骤。
摘要由CSDN通过智能技术生成

一、什么是gen_event

按照书上定义在OTP中,它由通用事件管理器进程组成,该进程具有动态添加和删除的任意数量的事件处理程序。事件可以是例如错误,警报或要记录的某些信息

简单来说,就是gen_event行为运行一个了一个事件管理进程,该进程接受消息(事件),并根据消息(事件)做对应的事件处理,而提供的对应事件处理其实就是添加的“回调函数”(事件处理器)。与gen_server不一样的是,他把回调的函数分类成多个module并称为事件处理器,需要注意的是事件处理器不是一个进程,看源码你会发现只是事件管理器进程里构造了一个记录列表,里面储存了对应的module和函数参数,必要时就调用。gen_event在游戏开发中除了在日记模块有用到,其他的地方几乎没有应用

二、如何使用

 

使用OTP事件管理器需要做四件事:

  1. 编写事件处理程序,
  2. 创建事件管理器,
  3. 向管理器添加处理程序,
  4. 通知事件管理器

以erlang趣学指南的冰球比赛为案例

事件管理器

-module(curling).
-export([start_link/2, set_teams/3, add_points/3, next_round/1]).
-export([join_feed/2, leave_feed/2]).
-export([game_info/1]).

start_link(TeamA, TeamB) ->
%%    创建事件管理进程
    {ok, Pid} = gen_event:start_link(),
    %% 添加事件处理器 gen_event:add_handler(事件管理进程pid, 回调模块, 参数),curling_scoreboard为计分板
    gen_event:add_handler(Pid, curling_scoreboard, []),
    %% accumulator为累加器
    gen_event:add_handler(Pid, curling_accumulator, []),
    set_teams(Pid, TeamA, TeamB),
    {ok, Pid}.

%%设置队伍
set_teams(Pid, TeamA, TeamB) ->
%%    事件通知
    gen_event:notify(Pid, {set_teams, TeamA, TeamB}).
%%添加分数
add_points(Pid, Team, N) ->
    gen_event:notify(Pid, {add_points, Team, N}).
%%下一回合
next_round(Pid) ->
    gen_event:notify(Pid, next_round).

%% Subscribes the pid ToPid to the event feed.
%% The specific event handler for the newsfeed is
%% returned in case someone wants to leave
%%join_feed(Pid, ToPid) ->
%%    HandlerId = {curling_feed, make_ref()},
%%    gen_event:add_sup_handler(Pid, HandlerId, [ToPid]),
%%    HandlerId.
%%
%%leave_feed(Pid, HandlerId) ->
%%    gen_event:delete_handler(Pid, HandlerId, leave_feed).

%% Returns the current game state.
game_info(Pid) ->
    gen_event:call(Pid, curling_accumulator, game_data).

事件处理器

-module(curling_scoreboard).
-behaviour(gen_event).

-export([init/1, handle_event/2, handle_call/2, handle_info/2, code_change/3,
         terminate/2]).

%%计分板
init([]) ->
    io:format("curling_scoreboard init ~n"),
    {ok, []}.

handle_event({set_teams, TeamA, TeamB}, State) ->
    io:format("curling_scoreboard set_teams ~n"),
    io:format("Scoreboard: Team ~s vs. Team ~s~n", [TeamA, TeamB]),
%%    curling_scoreboard_hw:set_teams(TeamA, TeamB),
    {ok, State};
handle_event({add_points, Team, N}, State) ->
    io:format("curling_scoreboard add_points ~n"),
    [io:format("Scoreboard: increased score of team ~s by 1~n", [Team]) || _ <- lists:seq(1,N)],
%%    [curling_scoreboard_hw:add_point(Team) || _ <- lists:seq(1,N)],
    {ok, State};
handle_event(next_round, State) ->
    io:format("curling_scoreboard next_round ~n"),
    io:format("Scoreboard: round over~n"),
%%    curling_scoreboard_hw:next_round(),
    {ok, State};
handle_event(_, State) ->
    {ok, State}.

handle_call(_, State) ->
    {ok, ok, State}.

handle_info(_, State) ->
    {ok, State}.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

terminate(_Reason, _State) ->
    ok.
-module(curling_accumulator).
-behaviour(gen_event).

-export([init/1, handle_event/2, handle_call/2, handle_info/2, code_change/3,
         terminate/2]).

-record(state, {teams=orddict:new(), round=0}).

%% 累加器

init([]) ->
    io:format("accumulator init ~n"),
    {ok, #state{}}.

handle_event({set_teams, TeamA, TeamB}, S=#state{teams=T}) ->
    io:format("accumulator set_teams ~n"),
    Teams = orddict:store(TeamA, 0, orddict:store(TeamB, 0, T)),
    {ok, S#state{teams=Teams}};
handle_event({add_points, Team, N}, S=#state{teams=T}) ->
    io:format("accumulator add_points ~n"),
    Teams = orddict:update_counter(Team, N, T),
    {ok, S#state{teams=Teams}};
handle_event(next_round, S=#state{}) ->
    io:format("accu
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值