首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在二郎调用gen_event?

如何在二郎调用gen_event?
EN

Stack Overflow用户
提问于 2019-12-22 17:28:27
回答 1查看 354关注 0票数 2

我使用的是gen_event行为,当我试图发出一个gen_event:call时,我会得到以下错误:

代码语言:javascript
复制
> =CRASH REPORT==== 22-Dec-2019::19:17:43.030000 ===   crasher:
>     initial call: gen_event:init_it/6
>     pid: <0.215.0>
>     registered_name: hev
>     exception exit: {undef,[{fm,state,[<0.215.0>],[]},
>                             {erl_eval,do_apply,6,
>                                       [{file,"erl_eval.erl"},{line,684}]},
>                             {shell,exprs,7,[{file,"shell.erl"},{line,686}]},
>                             {shell,eval_exprs,7,
>                                    [{file,"shell.erl"},{line,642}]},
>                             {shell,eval_loop,3,
>                                    [{file,"shell.erl"},{line,627}]}]}
>       in function  gen_event:terminate_server/4 (gen_event.erl, line 354)
>     ancestors: [<0.212.0>]
>     message_queue_len: 1
>     messages: [{'EXIT',<0.212.0>,normal}]
>     links: []
>     dictionary: []
>     trap_exit: true
>     status: running
>     heap_size: 610
>     stack_size: 27
>     reductions: 279   neighbours:

我的事件管理器和事件处理程序被生成,我可以成功地发出notify (我得到了ok ),但是我不能call

模块

代码语言:javascript
复制
-module(hev).
-export([start/0,append/2,state/1]).
-export([init/1,terminate/2,code_change/3,handle_call/2,handle_event/2]).
-record(state,{
    xs=[]
}).
-behaviour(gen_event).
%callbacks
init([])->
    {ok,#state{xs=[1]}}.

**API**

start()->
    {ok,Pid}=gen_event:start_link({local,?MODULE}),
    gen_event:add_handler(Pid,some_handler,[]),
    Pid.
append(Pid,Elem)->
    gen_event:notify(Pid,{append,Elem}).
state(Pid)->
    gen_event:call(Pid,state).

处理程序

代码语言:javascript
复制
handle_event({append,Elem},State=#state{xs=XS})->
    {ok,#state{xs=[Elem|XS]}};

handle_call(state,State})->     
    {ok,State,State};
handle_call(Event,State)->
    {ok,nada_for_you,State}.

P.S I没有发布所有的正则化方法(code_change,terminate..etc),但它们都存在。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-12-23 16:18:44

我没有发布所有的正则化方法(code_change,terminate..etc),但它们是存在的。

1)无论如何,它们都是可选的。检查文档中的大绿色注释,例如终止()

2)关于您的错误消息:

pid:<0.215.0> registered_name: hev异常出口:{undef,[{fm,state,<0.215.0>,[]},

它似乎在说,有一个进程(用pid=<0.215.0>)注册了名称hev,它试图用一个参数执行一个名为fm:state()的函数,但是没有在任何地方定义函数fm:state/1,因此出现undef异常。因为您没有发布名为fm的模块,所以这个错误与您发布的代码没有任何关系。

3)您的代码还指定了一个名为some_handler的模块,该模块不存在:

代码语言:javascript
复制
gen_event:add_handler(Pid,some_handler,[]),

4)这里有一个基本的语法错误:

代码语言:javascript
复制
 handle_call(state,State})-> 

5)使用错误的参数调用两个函数。

您需要更加勤奋地发布代码,这实际上会产生您所经历的错误。

下面是一个使用gen_event创建计数器的简单示例:

代码语言:javascript
复制
-module(counter).
-behaviour(gen_event).
-compile(export_all).

%% Callback functions:

init(StartingCount) ->  % Called by gen_event:add_handler()
    State = StartingCount,
    {ok, State}.

terminate(_Reason, State) ->
    io:format("Terminating state was: ~w~n", [State]).

% Calls to gen_event:notify() cause this function to execute:
handle_event({increase, Change}, State) -> 
    NewState = State+Change,
    {ok, NewState};
handle_event({decrease, Change}, State) ->
    NewState = State-Change,
    {ok, NewState}.

% Calls to gen_event:call() cause this function to execute:
handle_call(get_count, State) ->  
    Reply = io_lib:format("Reply from handle_call(): count is ~w~n", [State]),
    {ok, Reply, State};
handle_call({increase_and_get_count, Change}, State) ->
    NewState = State+Change,
    Reply = io_lib:format("Reply from handle_call(): count is ~w~n", [NewState]),
    {ok, Reply, NewState}.


%% User interface functions:

start(StartingCount) ->
    ServerName = gen_event_counter,
    CallbackModule = counter,

    {ok, _Pid} = gen_event:start_link({local, ServerName}),  
    %Name of process running gen_event server is: gen_event_counter

    ok = gen_event:add_handler(ServerName, CallbackModule, StartingCount). 
    %StartingCount is passed to init() callback


stop() ->
    ok = gen_event:stop(gen_event_counter),
    stopped.

send_request_with_notify(Request) -> 
    gen_event:notify(gen_event_counter, Request). % returns immediately, does not wait for a reply.
    % Request = {increase, 1}, {decrease, 2}, etc. 
    % Request is passed as first arg to handle_event().


send_request_with_call(Request) -> 
    Reply = gen_event:call(gen_event_counter, counter, Request), % waits for a reply  
    % Request is passed as first arg to handle_call()
    io:format("send_request_with_call() returned => ~s", [Reply]).

在外壳中:

代码语言:javascript
复制
~/erlang_programs/gen_event$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3  (abort with ^G)

1> c(counter).                                                 
counter.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,counter}

2> counter:start(0).                                           
ok

3> counter:send_request_with_call(get_count).                  
send_request_with_call() returned => Reply from handle_call(): count is 0
ok

4> counter:send_request_with_notify({increase, 2}).            
ok

5> counter:send_request_with_call(get_count).      
send_request_with_call() returned => Reply from handle_call(): count is 2
ok

6> counter:send_request_with_call({increase_and_get_count, 5}).
send_request_with_call() returned => Reply from handle_call(): count is 7
ok

7> counter:stop().                                             
Terminating state was: 7
stopped

8> 

在修复代码中的所有错误之后:

代码语言:javascript
复制
-module(hev).
-compile(export_all).
-behaviour(gen_event).

-record(state,{
    xs=[]
}).

%callbacks
init(no_args)->
    {ok, #state{xs=[1]} }.

handle_event({append,Elem}, #state{xs=XS} ) ->
    io:format("hev:handle_event() called~n"),
    {ok, #state{xs=[Elem|XS]}}.

handle_call(get_state, State)->     
    Reply = State,
    {ok, Reply, State};
handle_call(_Other, State)->
    Reply = nada_for_you,
    {ok, Reply, State}.

%**API**

start()->
    gen_event:start_link({local, ?MODULE}),  %Sets the gen_event server name to ?MODULE

    %                     Server   Callback  Args for
    %                     Name     module    init()
    gen_event:add_handler(?MODULE, ?MODULE, no_args). 
    %Tells the gen_event server named ?MODULE to look for the callback functions 
    %in a module also named ?MODULE

append(Elem)->
    %                Server    Request
    %                Name      (matches against 1st arg in handle_event() )
    gen_event:notify(?MODULE, {append, Elem}).

get_state()->
    %              Server   Calback  Request
    %              Name     module   (matches against 1st arg in handle_call() )
    gen_event:call(?MODULE, ?MODULE, get_state).

other_calls() ->
    gen_event:call(?MODULE, ?MODULE, {set_state, [1, 2, 3]}).


stop() ->
    ok = gen_event:stop(?MODULE),
    stopped.

在外壳中:

代码语言:javascript
复制
~/erlang_programs/gen_event$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3  (abort with ^G)

1> c(hev).         
hev.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,hev}

2> hev:start().    
ok

3> hev:get_state().
{state,[1]}

4> hev:append(45). 
ok
hev:handle_event() called

5> hev:get_state().
{state,[45,1]}

6> hev:other_calls().
nada_for_you

7> hev:stop().
stopped

8> 

注意,notify()使与add_handler()一起添加的所有模块中的handle_event()函数得以执行,而call()则以特定模块的handle_call()函数为目标。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59446507

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档