Erlang模块gen_fsm翻译
模块摘要
通用有限状态机行为。
描述
用于实现有限状态机的行为模块。使用该模块实现的通用有限状态机进程(gen_fsm)将具有一组标准的接口函数,并包括用于跟踪和错误报告的功能。它也适用于OTP监督树。有关更多信息,请参阅OTP设计原则。
gen_fsm假定所有特定部分都位于回调模块中,导出预定义的函数集。行为函数和回调函数之间的关系可以说明如下:
gen_fsm module Callback module
-------------- ---------------
gen_fsm:start_link -----> Module:init/1
gen_fsm:send_event -----> Module:StateName/2
gen_fsm:send_all_state_event -----> Module:handle_event/3
gen_fsm:sync_send_event -----> Module:StateName/3
gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
- -----> Module:handle_info/3
- -----> Module:terminate/3
- -----> Module:code_change/4
如果回调函数失败或返回错误值,gen_fsm将终止。
gen_fsm处理系统消息,如sys(3)中所述。该SYS模块可用于调试gen_fsm。
请注意,gen_fsm不会自动捕获退出信号,必须在回调模块中明确启动。
除非另有说明,否则如果指定的gen_fsm不存在或者给出了错误的参数,则此模块中的所有函数都将失败。
如果回调函数指定'hibernate'而不是超时值,gen_fsm进程可以进入休眠状态(参见erlang(3))。如果预计服务器长时间处于空闲状态,这可能很有用。但是,应谨慎使用此功能,因为休眠意味着至少有两个垃圾收集(在休眠时和唤醒后不久),对于忙的状态机器并不想在每一次调用之间处理垃圾回收。
导出
start_link(Module, Args, Options) -> Result
start_link(FsmName, Module, Args, Options) -> Result
Types:
FsmName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
Name = atom()
GlobalName = ViaName = term()
Module = atom()
Args = term()
Options = [Option]
Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}
Dbgs = [Dbg]
Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}
SOpts = [SOpt]
SOpt - 见erlang:spawn_opt/2,3,4,5
Result = {ok,Pid} | ignore | {error,Error}
Pid = pid()
Error = {already_started,Pid} | term()
创建gen_fsm进程作为监督树的一部分。该功能应由监督树直接或间接调用。除其他外,它将确保gen_fsm链接到监督树。
gen_fsm进程调用Module:init/1进行初始化。为确保同步启动过程,在Module:init/1返回之前,start_link/3,4不会返回。
如果FsmName = {local,Name},则gen_fsm使用register/2在本地注册为Name。如果FsmName = {global,GlobalName},则gen_fsm使用global:register_name/2全局注册为GlobalName。如果EventMgrName={via,Module,ViaName},则事件管理器注册用Module表示的注册表。所述模块的回调应该导出的函数register_name/2,unregister_name/1,whereis_name/1和send/2,其行为应与global中的相应函数相同。因此,{via,global,GlobalName}是有效的引用。
如果未提供名称,则不会注册gen_fsm。
Module是回调模块的名称。
Args是一个任意项,它作为参数传递给Module:init/1。
如果选项{timeout,Time}存在,则允许gen_fsm花费Time毫秒初始化,或者它将被终止,启动函数将返回 {error,timeout}。
如果存在选项{debug,Dbgs},则将为Dbgs中的每个项调用相应的sys函数。见sys(3)。
如果选项{spawn_opt,SOpts}存在,则SOpts将作为选项列表传递给spawn_opt BIF,后者用于生成gen_fsm进程。见erlang(3)。
注意
目前不允许使用spawn选项monitor,但会导致函数失败,原因为badarg。
如果gen_fsm成功创建并初始化,则函数返回{ok,Pid},其中Pid是gen_fsm的pid。如果已存在具有指定FsmName的进程,则该函数返回 {error,{already_started,Pid}},其中Pid是该进程的pid。
如果Module:init/1因Reason而失败,则函数返回{error,Reason}。如果Module:init/1返回{stop,Reason}或ignore,则进程终止,函数分别返回{error,Reason}或ignore。
start(Module, Args, Options) -> Result
start(FsmName, Module, Args, Options) -> Result
Types:
FsmName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
Name = atom()
GlobalName = ViaName = term()
Module = atom()
Args = term()
Options = [Option]
Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}
Dbgs = [Dbg]
Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}
SOpts = [term()]
Result = {ok,Pid} | ignore | {error,Error}
Pid = pid()
Error = {already_started,Pid} | term()
创建一个独立的gen_fsm进程,即gen_fsm,它不是监督树的一部分,因此没有监督者。
有关参数和返回值的说明,请参见start_link/3,4。
send_event(FsmRef, Event) -> ok
Types:
FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()
Event = term()
将事件异步发送到gen_fsm FsmRef并立即返回ok。gen_fsm将调用Module:StateName/2来处理事件,其中StateName是gen_fsm的当前状态的名称。
FsmRef可以是:
pid,
Name,如果gen_fsm在本地注册,
{Name,Node},如果gen_fsm在另一个节点本地注册,或者
{global,GlobalName},如果gen_fsm是全局注册的,
{via,Module,ViaName},如果事件管理器是通过可选进程注册表注册的,
Event是一个任意项,作为Module:StateName/2的参数之一传递。
send_all_state_event(FsmRef, Event) -> ok
Types:
FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()
Event = term()
将事件异步发送到gen_fsm FsmRef并立即返回ok。gen_fsm将调用Module:handle_event/3来处理事件。
有关参数的说明,请参阅send_event/2。
send_event和send_all_state_event之间的区别在于使用哪个回调函数来处理事件。在每个状态下发送事件以相同方式被处理,此函数很有用,因为在每个状态名称函数中只需要一个handle_event子句来处理事件而不是每个状态名函数一个子句。
sync_send_event(FsmRef, Event) -> Reply
sync_send_event(FsmRef, Event, Timeout) -> Reply
Types:
FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()
Event = term()
Timeout = int()>0 | infinity
Reply = term()
将事件发送到gen_fsm FsmRef并等待,直到回复到达或发生超时。gen_fsm将调用Module:StateName/3来处理事件,其中 StateName是gen_fsm的当前状态的名称。
有关FsmRef和Event 的说明,请参阅send_event/2。
Timeout是一个大于零的整数,它指定等待回复的毫秒数,或无限期等待的原子infinity。默认值为5000.如果在指定时间内未收到回复,则函数调用失败。
返回值Reply在Module:StateName/3的返回值中定义。
在OTP R12B/Erlang 5.6中删除了在连接到客户端时,如果服务器在调用期间挂了,有时会消耗服务器退出消息的古老行为。
sync_send_all_state_event(FsmRef, Event) -> Reply
sync_send_all_state_event(FsmRef, Event, Timeout) -> Reply
Types:
FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
Name = Node = atom()
GlobalName = ViaName = term()
Event = term()
Timeout = int()>0 | infinity
Reply = term()
将事件发送到gen_fsm FsmRef并等待,直到回复到达或发生超时。gen_fsm将调用Module:handle_sync_event/4来处理事件。
有关FsmRef和Event的说明,请参阅send_event/2。有关Timeout和Reply的说明,请参阅sync_send_event/3。
见send_all_state_event/2,讨论sync_send_event和sync_send_all_state_event的区别。
reply(Caller, Reply) -> true
Types:
Caller - 见下面
Reply = term()
当无法在Module:State/3或Module:handle_sync_event/4的返回值中定义回复时,gen_fsm可以使用此函数向客户端进程显式发送回复,当调用sync_send_event/2,3或sync_send_all_state_event/2,3。
Caller必须是提供给回调函数的From参数。Reply是一个任意项,它将作为sync_send_event/2,3或sync_send_all_state_event/2,3的返回值返回给客户端。
send_event_after(Time, Event) -> Ref
Types:
Time = integer()
Event = term()
Ref = reference()
在gen_fsm内部发送延迟事件,在time ms后调用此函数。使用cancel_timer/1可用于取消延迟发送的引用,立即返回。
gen_fsm将调用Module:StateName/2来处理事件,其中StateName是传递延迟事件时gen_fsm的当前状态的名称。
Event是一个任意项,作为Module:StateName/2的参数之一传递。
start_timer(Time, Msg) -> Ref
Types:
Time = integer()
Msg = term()
Ref = reference()
在gen_fsm内部发送超时事件,在Time ms后调用此函数。立即返回可用于使用cancel_timer/1取消计时器的引用。
gen_fsm将调用Module:StateName/2来处理事件,其中StateName是传递超时消息时gen_fsm的当前状态的名称。
Msg是一个任意的术语,它在超时消息{timeout,Ref,Msg}中传递,作为Module:StateName/2的参数之一。
cancel_timer(Ref) -> RemainingTime | false
Types:
Ref = reference()
RemainingTime = integer()
取消gen_fsm中Ref引用的内部计时器。
Ref是从send_event_after/2 或 start_timer/2返回的引用。
如果计时器已经超时,但事件尚未发送,则会被取消,就好像它没有超时一样,因此从此函数返回后将没有错误的计时器事件。
如果Ref引用活动计时器,则返回以毫秒为单位的剩余时间,直到计时器到期为止,否则返回false。
enter_loop(Module, Options, StateName, StateData)
enter_loop(Module, Options, StateName, StateData, FsmName)
enter_loop(Module, Options, StateName, StateData, Timeout)
enter_loop(Module, Options, StateName, StateData, FsmName, Timeout)
Types:
Module = atom()
Options = [Option]
Option = {debug,Dbgs}
Dbgs = [Dbg]
Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}
StateName = atom()
StateData = term()
FsmName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
Name = atom()
GlobalName = ViaName = term()
Timeout = int() | infinity
将现有进程转换为gen_fsm。不返回,而是调用进程将进入gen_fsm接收receive循环并成为gen_fsm进程。该进程必须使用proc_lib中的启动函数被启动,参看proc_lib(3)。用户对进程初始化负责,包括注册名字。
当需要比gen_fsm行为提供的更复杂的初始化过程时,此函数很有用。
Module,Options和FsmName与调用start[_link]/3,4时的含义相同。但是,如果指定了FsmName,则必须在调用此函数之前相应地注册该进程。
StateName,StateData和Timeout与Module:init/1的返回值具有相同的含义 。此外,回调模块Module不需要导出init/1功能。
失败:如果调用进程未由proc_lib启动函数启动,或者未根据FsmName注册。
回调函数
应从gen_fsm回调模块导出以下函数。
在描述中,表达式state name用于表示状态机的状态。state data用于表示实现状态机的Erlang进程的内部状态。
导出
Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate} | {error,Reason}
Types:
InitArgs = Args | {Args,Term}
Args = Term = term()
State = term()
Reason = term()
每当将新事件处理程序添加到事件管理器时,都会调用此函数来初始化事件处理程序。
如果添加了事件处理程序,由于调用gen_event:add_handler/3或gen_event:add_sup_handler/3,则InitArgs是这些函数的Args参数。
如果事件处理程序由于调用gen_event:swap_handler/3或gen_event:swap_sup_handler/3而替换另一个事件处理程序,或者由于来自其他一个回调函数的交换返回元组,则InitArgs是一个元组{Args,Term} 其中Args是函数call/return元组中提供的参数,Term是终止旧事件处理程序的结果,请参阅gen_event:swap_handler/3。
如果成功,该函数应返回{ok,State}或{ok,State,hibernate},其中State是事件处理程序的初始内部状态。
如果返回{ok,State,hibernate},则事件管理器将进入休眠状态(通过调用proc_lib:hibernate/3),等待下一个事件发生。
Module:StateName(Event, StateData) -> Result
Types:
Event = timeout | term()
StateData = term()
Result = {next_state,NextStateName,NewStateData}
| {next_state,NextStateName,NewStateData,Timeout}
| {next_state,NextStateName,NewStateData,hibernate}
| {stop,Reason,NewStateData}
NextStateName = atom()
NewStateData = term()
Timeout = int()>0 | infinity
Reason = term()
每个可能的状态名称应该有一个此函数的实例。每当gen_fsm接收到使用gen_fsm:send_event/2发送的事件时,将调用与当前状态名称StateName同名的此函数的实例来处理该事件。 如果发生超时,也会调用它。
事件是原子timeout,如果发生超时,Event提供参数给send_event/2。
StateData是gen_fsm的状态数据。
如果函数返回{next_state,NextStateName,NewStateData},{next_state,NextStateName,NewStateData,Timeout}或{next_state,NextStateName,NewStateData,hibernate},gen_fsm将继续执行,当前状态名称设置为NextStateName并且可能更新状态数据NewStateData。 有关Timeout和hibernate的说明,请参阅Module:init/1。
如果函数返回{stop,Reason,NewStateData},gen_fsm将调用Module:terminate(Reason,NewStateData)并终止。
Module:handle_event(Event, StateName, StateData) -> Result
Types:
Event = term()
StateName = atom()
StateData = term()
Result = {next_state,NextStateName,NewStateData}
| {next_state,NextStateName,NewStateData,Timeout}
| {next_state,NextStateName,NewStateData,hibernate}
| {stop,Reason,NewStateData}
NextStateName = atom()
NewStateData = term()
Timeout = int()>0 | infinity
Reason = term()
每当gen_fsm接收到使用gen_fsm:send_all_state_event/2发送的事件时,就会调用此函数来处理该事件。
StateName是gen_fsm的当前状态名称。
有关其他参数和可能的返回值的说明,请参阅Module:StateName/2。
Module:StateName(Event, From, StateData) -> Result
Types:
Event = term()
From = {pid(),Tag}
StateData = term()
Result = {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}
Reply = term()
NextStateName = atom()
NewStateData = term()
Timeout = int()>0 | infinity
Reason = normal | term()
每个可能的状态名称应该有一个此函数的实例。每当gen_fsm接收到使用gen_fsm:sync_send_event/2,3发送的事件时,将调用与当前状态名称StateName同名的此函数的实例来处理该事件。
Event是提供给sync_send_event的Event参数。
From是一个元组{Pid,Tag},其中Pid是名为sync_send_event/2,3进程的pid,Tag是唯一标记。
StateData是gen_fsm的状态数据。
如果函数返回{reply,Reply,NextStateName,NewStateData},{reply,Reply,NextStateName,NewStateData,Timeout}或{reply,Reply,NextStateName,NewStateData,hibernate},则Reply将给回到From作为sync_send_event/2,3的返回值。然后gen_fsm继续执行,当前状态名称设置为NextStateName,并且可能更新状态数据NewStateData。有关Timeout和hibernate的说明,请参阅Module:init/1。
如果函数返回{next_state,NextStateName,NewStateData},{next_state,NextStateName,NewStateData,Timeout}或{next_state,NextStateName,NewStateData,hibernate},gen_fsm将继续使用NewStateData在NextStateName中执行。必须使用gen_fsm:reply/2明确给出对From的任何回复。
如果函数返回{stop,Reason,Reply,NewStateData},则回复将返回From。如果函数返回{stop,Reason,NewStateData},则必须使用gen_fsm:reply/2显式给出对From的任何回复。然后gen_fsm将调用Module:terminate(Reason,NewStateData)并终止。
Module:handle_sync_event(Event, From, StateName, StateData) -> Result
Types:
Event = term()
From = {pid(),Tag}
StateName = atom()
StateData = term()
Result = {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}
Reply = term()
NextStateName = atom()
NewStateData = term()
Timeout = int()>0 | infinity
Reason = term()
每当gen_fsm接收到使用gen_fsm:sync_send_all_state_event/2,3发送的事件时,将调用此函数来处理该事件。
StateName是gen_fsm的当前状态名称。
有关其他参数和可能的返回值的说明,请参阅Module:StateName/3。
Module:handle_info(Info, StateName, StateData) -> Result
Types:
Info = term()
StateName = atom()
StateData = term()
Result = {next_state,NextStateName,NewStateData}
| {next_state,NextStateName,NewStateData,Timeout}
| {next_state,NextStateName,NewStateData,hibernate}
| {stop,Reason,NewStateData}
NextStateName = atom()
NewStateData = term()
Timeout = int()>0 | infinity
Reason = normal | term()
当gen_fsm接收到除同步或异步事件(或系统消息)之外的任何其他消息时,将调用此函数。
Info是收到的消息。
有关其他参数和可能的返回值的说明,请参阅Module:StateName/2。
Module:terminate(Reason, StateName, StateData)
Types:
Reason = normal | shutdown | {shutdown,term()} | term()
StateName = atom()
StateData = term()
当gen_fsm即将终止时,该函数被gen_fsm调用。它应该与Module:init/1相反,并进行任何必要的清理。返回时,gen_fsm以Reason结束。返回值被忽略。
Reason是表示停止原因的术语,StateName是当前状态名称,StateData是gen_fsm的状态数据。
Reason取决于gen_fsm为何终止。如果是因为另一个回调函数返回了一个停止元组{stop,..},则Reason将具有该元组中指定的值。如果是由于失败,则Reason是错误原因。
如果gen_fsm是监督树的一部分并且由其主管命令终止,则如果满足以下条件,则将使用Reason = shutdown调用此函数:
gen_fsm已被设置为捕获退出信号,并且监督者的子规范中定义的关闭策略是整数超时值,而不是brutal_kill。
即使gen_fsm不是监督树的一部分,如果它从其父级接收到“EXIT”消息,也将调用该函数。Reason与“EXIT”消息中的原因相同。
否则,gen_fsm将立即终止。
请注意,除了正常,关闭或{shutdown,Term}之外的任何其他原因,假定gen_fsm由于错误而终止,并且使用error_logger:format/2发出错误报告。
Module:code_change(OldVsn, StateName, StateData, Extra) -> {ok, NextStateName, NewStateData}
Types:
OldVsn = Vsn | {down, Vsn}
Vsn = term()
StateName = NextStateName = atom()
StateData = NewStateData = term()
Extra = term()
当gen_fsm在发布升级/降级期间更新其内部状态数据时,即在appup文件中给出Change= {advanced,Extra}的指令{update,Module,Change,...}时,将调用此函数。 见OTP设计原则。
在升级的情况下,OldVsn是Vsn,在降级的情况下,OldVsn是{down,Vsn}。 Vsn由旧版本的回调模块Module的vsn属性定义。 如果未定义此类属性,则版本是BEAM文件的校验和。
StateName是当前状态名称,StateData是gen_fsm的内部状态数据。
Extra从更新指令的{advanced,Extra}部分按原样传递。
该函数应返回新的当前状态名称和更新的内部数据。
Module:format_status(Opt, [PDict, StateData]) -> Status
Types:
Opt = normal | terminate
PDict = [{Key, Value}]
StateData = term()
Status = term()
请注意,该回调可选,所以回调模块不需要导出它,这个回调模块提供一个默认实现,该函数返回回调模块状态。
在以下情况下,gen_fsm进程会调用此函数:
调用sys:get_status/1,2之一以获取gen_fsm状态。对于这种情况,Opt设置为原子normal。
gen_fsm异常终止并记录错误。对于这种情况,选项设置为原子terminate。
此函数可用于自定义这些情况的gen_fsm状态的形式和外观。希望自定义sys:get_status/1,2返回值以及其状态如何在终止错误日志中出现的回调模块导出format_status/2的实例,该实例返回描述gen_fsm当前状态的术语。
PDict是gen_fsm的进程字典的当前值。
StateData是gen_fsm的内部状态数据。
该函数应返回Status,这是一个定制gen_fsm当前状态和状态详细信息的术语。状态可以采取的形式没有限制,但对于sys:get_status/1,2情况(当Opt是normal时),Status值的推荐形式为[{data,[{“StateData”,Term}]其中Term提供gen_fsm状态数据的相关详细信息。不需要遵循此建议,但这样做会使回调模块状态与sys:get_status/1,2返回值的其余部分保持一致。
此函数的一个用途是返回紧凑的替代状态数据表示,以避免在日志文件中打印大的状态术语。