为什么gen_fsm状态方法必须返回某些内容?

时间:2019-10-29 19:54:27

标签: erlang otp fsm

我目前正在阅读LYAE,并且我试图了解为什么gen_fsm状态方法必须根据source完全返回任何内容

{reply, Reply, NextStateName, NewStateData}
{reply, Reply, NextStateName, NewStateData, Timeout}
{reply, Reply, NextStateName, NewStateData, hibernate}

{next_state, NextStateName, NewStateData}
{next_state, NextStateName, NewStateData, Timeout}
{next_state, NextStateName, NewStateData, hibernate}

{stop, Reason, Reply, NewStateData}
{stop, Reason, NewStateData}

如果我有3种状态方法:abc,有人可以向我解释,状态机的定义如下:

a()->
  receive
    something -> b();
    _ -> error(err)
  end.

b()->
  receive 
    somethingelse-> c();
    _ ->
  end.

为什么我需要下一个状态方法的返回结果?

someMethod()->
   receive 
      _ -> 
           {next_state, NextStateName, NewStateData}=someNextMethod(),
          //why would i place code here? What could i possibly do with the above tuple ?
   end.

我不明白为什么我要在调用代码后再调用下一个状态方法?所有调用都是递归的,所以除了初始状态(在fsm结束或抛出之后我实际上可以执行某些操作)之外,为什么还要在其他状态下放置代码?

2 个答案:

答案 0 :(得分:3)

您是正确的,不需要返回值,并且必须对将要在接收语句上等待的某些函数进行递归调用:有必要使事情发展(由于变量的不变性)并做出反应到一条新消息。

重点是您的示例是一个模块状态机,而当您使用gen_fsm行为时,至少有两个模块在起作用:

  • 隐式且通用的gen_fsm行为模块本身
  • 以及您正在编写的特定回调模块。

每个模块的角色都非常不同。

  • 通用消息负责保持状态并接收消息(这就是为什么您不能在代码中处理此消息的原因),它提供了不同类型的消息:同步或异步,到一个状态或任何状态,通过gen_fsm接口或“自由发送”消息...它还管理以下操作模式:初始化,停止,代码更改...它还在后台管理与OTP系统的接口。由于它是通用模块,因此无法知道要定义的状态和转换。
  • gen_fsm几乎在每次收到消息时都会调用回调模块。调用的函数取决于状态和消息。回调模块负责定义状态机所需的状态和转换,它是通过将返回值发送回gen_fsm来完成的。返回值包含多个字段,下一个状态是强制性的,因为gen_fsm必须知道要进入哪个状态-进入状态是映像,它只是存储在变量中并由主fsm循环维护的状态名称-它也可以维护更多信息(通常也称为状态信息,这令人困惑,例如,对于门锁系统而言,当前的密码)。返回值还可能包含其他内容,例如在出现同步消息的情况下对呼叫者的答复,在下一个传入消息之前的超时,停止fsm的请求...

简而言之,gen_fsm是一个简单的递归循环,等待“事件”消息,这些消息至少维护State_name变量。它使用存储在回调模块中的辅助函数来描述其行为。与您所说的相距不远,但受到通用模块带来的限制-以及集成到OTP和经过验证的代码的优势。

答案 1 :(得分:2)

   {next_state, NextStateName, NewStateData}=someNextMethod(),
   //why would i place code here? What could i possibly do with the above tuple ?

例如:

  {next_state, NextStateName, NewStateData}=someNextMethod(),
  {next_state, NextStateName, NewStateData + 1}

或者:

  {next_state, NextStateName, NewStateData}=someNextMethod(),
  ModifiedStateData = do_calculation(NewStateData),
  {next_state, NextStateName, ModifiedStateData}
相关问题