为什么此gen_statem调用受阻?

时间:2019-12-16 18:45:09

标签: erlang fsm

您好,由于我的fsm在单独的进程中运行,因此我试图找出使用gen_statem的原因为何会阻止调用。

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

-export([state/1,start/0,interview/2,reject/2,wait/1]).

-export([sitting_home/3,interviewing/3]).
-export([handle_event/3]).
-behaviour(gen_statem).

handle_event({call,From},get_state,Data)->
    io:format("why you need state>"),
    {keep_state,Data};
handle_event({call,From},Event,Data)->
    {keep,state,Data}.
%API
start()->
    gen_statem:start_link(?MODULE,[],[]).
state(PID)->
    gen_statem:call(PID,get_state).

interview(PID,Company)->
    gen_statem:call(PID,{intv,Company}).
reject(PID,Company)->
    gen_statem:call(PID,{reject,Company}).
wait(PID)->
    gen_statem:call(PID,{wait}).

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

% State implementations

sitting_home({call,From},{intv,Company},Data=#data{intvCount=C})->
    io:format("called for interview"),
    {next_state,interviewing,Data#data{intvCount=C+1},{reply,From,something}};
sitting_home({call,From},Event,Data)->
    {keep_state,Data}.

interviewing({call,From},{rejected,Company},Data)->
    {next_state,sitting_home,Data,{reply,From,somethingelse}};
interviewing({call,From},wait,Data)->
    {keep_state,Data}.

用法

>{ok,Pid}=fsm:start().
>fsm:state(). //blocks !

>{ok,Pid}=fsm:start().
>fsm:interview(Pid).
 called for interview %and blocks

为什么两个电话都阻塞?除了使用fsm在其中运行gen_statem:start_link的外壳程序外,我还产生了一个不同的进程。 为什么在两种情况下都会阻止?

更新 在我被指出我忘记使用reply以便将某些内容发送回呼叫者之后,我已经更新了帖子。但是handle_event/3仍然以这种形式阻止:

handle_event({call,From},get_state,Data)->
    {keep_state,Data,[{reply,From,Data}]}.

1 个答案:

答案 0 :(得分:2)

因为gen_statem:call就是这样做的:

  通过发送请求并等待其回复到达

,对gen_statem ServerRef进行同步调用

,您的状态函数不会发送任何答复。它们应该看起来像

sitting_home({call,From},{intv,Company},Data=#data{intvCount=C})->
    io:format("called for interview"), 
    {next_state,interviewing,Data#data{intvCount=C+1},{reply,From,WhateverReplyYouWant}};

sitting_home({call,From},{intv,Company},Data=#data{intvCount=C})->
    io:format("called for interview"), 
    gen_statem:reply(From, WhateverReplyYouWant),
    {next_state,interviewing,Data#data{intvCount=C+1}};

如果没有有用的答复,请考虑

  1. 使用cast代替call(并在状态函数中将cast作为EventType处理),或

  2. ok作为答复。