[我正在使用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").
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