【问题标题】:erlang gen_statem: error bad_return_from_state_functionerlang gen_statem:错误 bad_return_from_state_function
【发布时间】:2019-07-27 20:11:17
【问题描述】:

我遇到了一个奇怪的问题。我得到了这个FSM(代码的内容不是那么无能,所以我把它去掉了,现在你只能看结构了):

start_link() ->
  gen_statem:start_link({local, ?MODULE}, ?MODULE, [], []).


init([]) ->
  io:format ("init", []),
  Data={1},
  {ok, packetsDeliver, Data}.


callback_mode() ->
  [state_functions, state_enter].


packetsDeliver(enter, _OldState, Data) ->
  io:format ("Key1", []),
  {keep_state, Data};

packetsDeliver(info, _OldState, Data) ->
  io:format ("Key2", []),
  {keep_state, Data};


packetsDeliver(cast, _PacketData, Data) ->
  io:format ("Key3", []),
      {next_state, allPacketsDelivered, Data}.

allPacketsDelivered(enter, _OldState, Data) ->
  io:format ("Key4", []),
  {next_state, packetsDeliver , Data}.

我尝试了几件事没有任何成功,我认为写作

{next_state, packetsDeliver , Data}.

会给我状态:

packetsDeliver(enter, _OldState, Data)

但是我得到了这个错误:

exception exit: {bad_return_from_state_function,
                       {next_state,packetsDeliver,{1}}}
     in function  gen_statem:loop_event_result/9 (gen_statem.erl, line 1165)
     in call from proc_lib:init_p_do_apply/3 (proc_lib.erl, line 247)
3> 
=ERROR REPORT==== 27-Jul-2019::23:53:35 ===
** State machine test terminating
** Last event = {cast,1}
** When server state  = {allPacketsDelivered,{1}}
** Reason for termination = error:{bad_return_from_state_function,
                                      {next_state,packetsDeliver,{1}}}
** Callback mode = [state_functions,state_enter]
** Stacktrace =
**  [{gen_statem,loop_event_result,9,[{file,"gen_statem.erl"},{line,1165}]},
     {proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,247}]}]

另一个问题/问题是我不知道为什么状态

packetsDeliver(enter, _OldState, Data) ->
  io:format ("Key1", []),
  {keep_state, Data};

正在把我送到 packetDeliver(info, _OldState, Data) 我什么时候做keep_state?

【问题讨论】:

  • 您是否在 start_link() 或某些事件被强制转换到 FSM 后遇到此崩溃?

标签: erlang fsm


【解决方案1】:

看看你的状态enter函数为packetsDeliver返回了什么:

packetsDeliver(enter, _OldState, Data) ->
  io:format ("Key1", []),
  {keep_state, Data};   %% <====== HERE

现在看看你的 State cast 函数为 packetsDeliver 返回了什么:

packetsDeliver(cast, _PacketData, Data) ->
  io:format ("Key3", []),
  {next_state, allPacketsDelivered, Data}.  %% <===== HERE

现在看看你的 State enter 函数为 allPacketsDelivered 返回了什么:

allPacketsDelivered(enter, _OldState, Data) ->
  io:format ("Key4", []),
  {next_state, packetsDeliver , Data}.  %% <==== HERE

allpacketsDelivered 的 State enter 函数应该返回一个类似于 packetsDelivered 的 State enter 函数的元组,例如{keep_state, ...} 不是 {next_state, ...}。

来自the docs,这些是状态enter 函数的允许返回值:

state_callback_result(ActionType) = 
    {keep_state, NewData :: data()} |
    {keep_state,
     NewData :: data(),
     Actions :: [ActionType] | ActionType} |
    keep_state_and_data |
    {keep_state_and_data, Actions :: [ActionType] | ActionType} |
    {repeat_state, NewData :: data()} |
    {repeat_state,
     NewData :: data(),
     Actions :: [ActionType] | ActionType} |
    repeat_state_and_data |
    {repeat_state_and_data, Actions :: [ActionType] | ActionType} |
    stop |
    {stop, Reason :: term()} |
    {stop, Reason :: term(), NewData :: data()} |
    {stop_and_reply,
     Reason :: term(),
     Replies :: [reply_action()] | reply_action()} |
    {stop_and_reply,
     Reason :: term(),
     Replies :: [reply_action()] | reply_action(),
     NewData :: data()}

请注意,{next_state, ...} 不是允许的返回值之一,这就是您收到错误 bad_return_from_state_function 的原因。 docs 也说:

当 gen_statem 与 state enter 调用一起运行时,这些函数是 在每个状态期间也使用参数(enter, OldState, ...) 调用 改变。在这种情况下,对以下操作有一些限制 可能会返回:由于状态输入调用是不允许的,因此推迟()是不允许的 不是事件,因此没有事件可以推迟,并且 {next_event,_,_} 是不允许的,因为使用状态输入调用应该 不影响事件的消费和生产方式。 您也可能不会 从此调用更改状态。如果你回来 {next_state,NextState, ...} 和 NextState =/= State gen_statem 崩溃。 请注意,它实际上是允许使用的 {repeat_state, NewData, ...} 虽然这没什么意义,因为你 立即将再次以新状态调用 enter call making 这只是一种奇怪的循环方式,还有更好的循环方式 二郎。如果您不更新 NewData 并且有一些循环终止 条件,或者如果您使用 {repeat_state_and_data, _} 或 repeat_state_and_data 你有一个无限循环!建议您 使用 {keep_state,...}、{keep_state_and_data,_} 或 keep_state_and_data 因为无论如何都无法从状态输入调用更改状态。

======

另一个问题/问题是我不知道为什么状态

packetsDeliver(enter, _OldState, Data) ->
  io:format ("Key1", []),
  {keep_state, Data};

当我这样做时,正在将我送到 packetDeliver(info, _OldState, Data) 保持状态?

when I do keep_state 是什么意思?我可以告诉你这对任何阅读你的问题的人意味着什么:绝对没有。

当我do keep_state 时,该信息回调不会执行。这样就可以准确地告诉您如何修复代码,对吗?错了。

我是这样做的:

send_event() ->
    gen_statem:cast(?MODULE, hello).

如果你这样做:

Pid ! {blah, blah}

然后将执行当前状态的info 回调。

完整示例:

-module(packets).
-behavior(gen_statem).
-compile(export_all).

start_link() ->
    gen_statem:start_link({local, ?MODULE}, ?MODULE, [], []).

init([]) ->
    io:format ("init~n"),
    Data=1,
    {ok, packetsDeliver, Data}.  
    %The initial state will be packetsDeliver.
    %And, when you transition to a state, and you 
    %have specified state_enter, then the function
    %State(enter, OldState, Data) will execute, which
    %in this case is packetsDeliver(enter, OldState, Data)

callback_mode() ->
    [state_functions, state_enter].

packetsDeliver(enter, _OldState, Data) ->
    io:format("packetsDeliver enter~n"),
    {keep_state, Data};
packetsDeliver(cast, _Msg, Data) ->
    io:format ("packetsDeliver cast~n"),
    {next_state, allPacketsDelivered, Data};
packetsDeliver(info, _Msg, Data) ->
    io:format("packetsDeliver info~n"),
    {keep_state, Data}.

allPacketsDelivered(enter, _OldState, _Data) ->
    io:format("allPacketsDelivered enter~n"),
    %{next_state, packetsDeliver , Data}.
    {keep_state_and_data, []}.

send_event() ->
    gen_statem:cast(?MODULE, hello).

在外壳中:

~/erlang_programs/gen_statem$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3  (abort with ^G)

1> c(packets).                  
packets.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,packets}

2> packets:start_link().                     
init
packetsDeliver enter
{ok,<0.71.0>}

3> Pid = whereis(packets).
<0.71.0>

4> Pid ! hello.
packetsDeliver info
hello

5> packets:send_event().
packetsDeliver cast
ok
allPacketsDelivered enter

6> 

【讨论】:

    猜你喜欢
    • 2021-08-12
    • 2020-06-16
    • 1970-01-01
    • 2018-08-26
    • 2019-01-30
    • 2015-02-14
    • 2019-02-06
    • 2016-06-01
    • 2012-05-16
    相关资源
    最近更新 更多