为什么这个 gen_statem 呼叫阻塞?
Why is this gen_statem call blocking?
你好,我想弄清楚在使用 gen_statem
时为什么调用会阻塞,因为我的 fsm 运行 在一个单独的进程中。
-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
为什么两个调用都阻塞?除了 shell 之外,我正在生成一个不同的进程,其中 fsm
使用 gen_statem:start_link
运行。
为什么在这两种情况下它都会阻塞?
更新
在有人指出我忘记使用 reply
以便将某些内容发送回 caller.However 之后,我更新了我的 post,即使以这种形式,handle_event/3
仍然会阻塞:
handle_event({call,From},get_state,Data)->
{keep_state,Data,[{reply,From,Data}]}.
因为那是 gen_statem:call
所做的:
Makes a synchronous call to the gen_statem ServerRef by sending a request and waiting until its reply arrives
并且您的状态函数不发送任何回复。它们应该看起来像
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}};
如果没有有用的回复,请考虑
使用 cast
而不是 call
(并将 cast
作为状态函数中的 EventType
处理),或
ok
作为回复。
你好,我想弄清楚在使用 gen_statem
时为什么调用会阻塞,因为我的 fsm 运行 在一个单独的进程中。
-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
为什么两个调用都阻塞?除了 shell 之外,我正在生成一个不同的进程,其中 fsm
使用 gen_statem:start_link
运行。
为什么在这两种情况下它都会阻塞?
更新
在有人指出我忘记使用 reply
以便将某些内容发送回 caller.However 之后,我更新了我的 post,即使以这种形式,handle_event/3
仍然会阻塞:
handle_event({call,From},get_state,Data)->
{keep_state,Data,[{reply,From,Data}]}.
因为那是 gen_statem:call
所做的:
Makes a synchronous call to the gen_statem ServerRef by sending a request and waiting until its reply arrives
并且您的状态函数不发送任何回复。它们应该看起来像
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}};
如果没有有用的回复,请考虑
使用
cast
而不是call
(并将cast
作为状态函数中的EventType
处理),或ok
作为回复。