无法在 Erlang 中运行 fsm
Posted
技术标签:
【中文标题】无法在 Erlang 中运行 fsm【英文标题】:Can not run fsm in Erlang 【发布时间】:2020-04-05 06:46:59 【问题描述】:您好,我正在尝试在与调用者不同的进程中使用gen_statem
运行fsm
。我还尝试将调用者保留在其状态参数中,以便在每次状态更改后对其进行更新。
我不断收到此错误:
** State machine <0.123.0> terminating
** Last event = internal,init_state
** When server state = sitting_home,state,"None",0,0,[<0.116.0>]
** Reason for termination = error:'function not exported',
fsm,callback_mode,0
** Callback mode = undefined
** Stacktrace =
** [gen_statem,call_callback_mode,1,[file,"gen_statem.erl",line,1610],
gen_statem,enter,7,[file,"gen_statem.erl",line,679],
proc_lib,init_p_do_apply,3,[file,"proc_lib.erl",line,249]]
=CRASH REPORT==== 12-Dec-2019::00:14:42.717000 ===
crasher:
initial call: fsm:init/1
pid: <0.123.0>
registered_name: []
exception error: undefined function fsm:callback_mode/0
in function gen_statem:call_callback_mode/1 (gen_statem.erl, line 1610)
in call from gen_statem:enter/7 (gen_statem.erl, line 679)
ancestors: [<0.116.0>]
message_queue_len: 0
messages: []
links: []
dictionary: []
trap_exit: false
status: running
heap_size: 1598
stack_size: 27
reductions: 5805
neighbours:
我查看了 erlang 文档,我发现没有回调 mode
需要实现 here。
模块
-module(fsm).
-record(state,
current="None",
intvCount=0,
jobCount=0,
monitor
).
-export([init/1,start/0]).
-export([hire/2,fire/1,interview/2]).
-behaviour(gen_statem).
start()->
gen_statem:start(?MODULE,[self()],[]).
init(Monitor)->
ok,sitting_home,#statecurrent="None",jobCount=0,intvCount=0,monitor=Monitor.
sitting_home(intv,Company,State=#stateintvCount=C,monitor=M)->
gen_statem:reply(M,"Got an interview from:"++Company++" going interviewing"),
next_state,interviewing,State#stateintvCount=C+1;
sitting_home(Event,State)->
gen_statem:reply(State#state.monitor,unexpected , Event),
next_state,sitting_home,State.
interviewing(rejected,Company,State)->
gen_statem:reply("Booh got rejected by :"++ Company),
next_state,sitting_home,State;
interviewing(accepted,Company,State=#statejobCount=J)->
gen_statem:reply("Hooray got accepted"),
next_state,working,State#statejobCount=J+1,current=Company;
interviewing(_,State)->
gen_statem:reply("Unknown message"),
next_state,interviewing,State.
working(fire,State=#statecurrent=C)->
gen_statem:reply("Unexpected event"),
next_state,working,State#statecurrent="None";
working(Event,State)->
gen_statem:reply("Unexpected event"),
next_state,working,State.
活动
hire(Company,PID)->
gen_statem:sync_send_event(PID,hire,self(),Company,0).
fire(PID)->
gen_statem:sync_send_event(PID,fire,self(),0).
interview(Company,PID)->
gen_state:sync_send_event(PID,intv,Company,0).
P.S我使用 gen_statem
是因为 shell 告诉我 gen_fsm
已弃用。我不知道 sync_send_event
的等效项。这可能是问题吗?
【问题讨论】:
【参考方案1】:Module:callback_mode
is documented 在您链接的页面上。当您为每个状态(sitting_home
、interviewing
等)都有一个函数时,它应该是
callback_mode() -> state_functions.
状态函数采用 3 个参数,而不是 2 个。您缺少第一个参数,EventType
,在您的情况下应该是 call, From
。
sync_send_event
的等价物可以是 call
,但是你的状态函数应该总是回复。
您可以在回调的返回值中组合reply
和next_state
,例如
working(Event,State)->
gen_statem:reply("Unexpected event"),
next_state,working,State.
可以变成
working(call, From, Event, State)->
next_state, working, State, reply, From, "Unexpected event".
即使你不这样做,reply
needs a From
argument:
working(call, From, Event, State)->
gen_statem:reply(From, "Unexpected event"),
next_state,working,State.
【讨论】:
好的,所以使用 gen_statem 我的所有状态都必须有 3 个参数,其中一个是Call/cast,From
。如果是这种情况,我仍然没有在返回中得到 reply,From,Message
参数。此问题是否会发出 gen_statem:reply
进行回复并返回状态?
1. “其中之一是 Call/cast,From”call, From
/cast
/timeout
/等。但不是cast,From
。 2. 是的,您可以将一个动作或动作列表作为元组的第四个组成部分。不仅是回复,还允许其他操作。见erlang.org/doc/man/gen_statem.html#type-event_handler_result。
但是我在调用 reply
时没有得到语法: function name, argument
导致调用该方法。是特定于 gen_statem
的约定还是特定于 erlang 的?跨度>
特定于gen_statem
。而reply, From, "Unexpected event"
这里是一个动作(erlang.org/doc/man/gen_statem.html#type-action),只和函数名重合。以上是关于无法在 Erlang 中运行 fsm的主要内容,如果未能解决你的问题,请参考以下文章
运行 N 个 Erlang 节点并使用 bash 脚本在每个节点中执行一行
Rebar3 版本无法运行并崩溃,无法在引导文件中扩展 $ERTS_LIB_DIR