我的gen_statem fsm实现有什么问题?

问题描述 投票:1回答:1

[我正在使用gen_statem模块实现gen_fsm,并且当我尝试检查其状态为handle_event_function时出现以下错误:

> ** exception error: {function_clause,
>                         {gen_statem,call,[{ok,<0.139.0>},state,0]}}
>      in function  gen:do_for_proc/2
>         called as gen:do_for_proc({ok,<0.139.0>},#Fun<gen.0.9801092>)
>      in call from gen_statem:'-call_clean/4-fun-0-'/5 (gen_statem.erl, line 637) 25> c("C:/Erlang/Genserv/fsm.erl").

下面是我的代码,分为:

-mandatory methods for the fsm to work
-api that the client can use (state change,get the state,start)
- generic handlers for when client demands something related to state
-state implementations

模块

-module(fsm).
-record(state,{
    current="None",
    intvCount=0,
    jobCount=0
}).
-export([init/1,terminate/3,callback_mode/0,code_change/4]).

-export([state/1,start/0,hire/2,fire/2,interview/2]).

-export([sitting_home/3,interviewing/3,working/3]).

-behaviour(gen_statem).

%API
start()->
    gen_statem:start_link(?MODULE,[],[]).
state(PID)->
    gen_statem:call(PID,state,0).
hire(PID,Company)->
    gen_statem:call(PID,{hire,Company},0).
fire(PID,Company)->
    gen_statem:call(PID,{fire,Company},0).
interview(PID,Company)->
    gen_state:call(PID,{intv,Company},0).

%mandatory
code_change(V,State,Data,Extra)->{ok,State,Data}.
callback_mode() ->
    [state_functions,handle_event_function].
init([])->
    {ok,sitting_home,#state{current="None",jobCount=0,intvCount=0}}.
terminate(Reasom,State,Data)->
    void.

% Generic handlers
handle_event({call,From},state,State)->
    {keep_state,State,[{reply,From,State}]};
handle_event(_,_,State)->
    {keep_state,State}.

% State implementations
sitting_home({call,From},{intv,Company},State=#state{intvCount=C})->
     {next_state,interviewing,State#state{intvCount=C+1},[{reply,From,"Interviewing by:"++Company}]};
sitting_home(EventType,Event,State)->
     handle_event(EventType,Event,State).
interviewing({call,From},{rejected,Company},State)->
    {next_state,sitting_home,State,[{reply,From,"rejected by:"++Company}]};
interviewing({call,From},{accepted,Company},State=#state{jobCount=J})->
    {next_state,
    working,
    State#state{jobCount=J+1,current=Company},
    [{reply,From,"accepted offer from:"++Company}]
};
interviewing(EventType,Event,State)->
    handle_event(EventType,Event,State).


working({call,From},{fire,Company},State=#state{current=C})->
    {next_state,working,State#state{current="None"},[{reply,From,"Got fired from"++Company}]};
working(EventType,Event,State)->
      handle_event(EventType,Event,State).

用法

FSM_PID=fsm:start().
fsm:state(PID). //crashes when demanding state
fsm:hire(PID,"Some Company").
erlang fsm
1个回答
3
投票

fsm:start()返回元组{ok,Pid}。您不能在下一次调用中直接使用函数的返回值。相反,您必须执行以下操作:

{ok,P} = fsm:start().
fsm:state(P).

然后您将遇到其他麻烦,第一个是您将超时指定为0,因此会出现超时错误。您将不得不更改它,然后继续调试:o)

[编辑]

您无需指定Pid,它是通过gen_statem代码在后台完成的,gen_statem:call函数在调用者上下文中执行,因此它仍然可以访问调用者Pid

实际上,它稍微复杂一点,取决于是否指定超时,gen_statem:call/3将产生一个进程来调用gen:call/4函数或直接调用它,因此Pid发送到状态计算机将是派生函数的一个或调用者的一个。

[gen:call/4还向状态机添加消息中的Reference以“签名”答案,并保证从应用程序其他任何部分传入的消息都不会被解释为答案。

这是erlang(和编程)中的一种通用模式,用于在接口功能中尽可能多地隐藏系统机制。就像您在函数state/1

中所做的一样
© www.soinside.com 2019 - 2024. All rights reserved.