查看源代码 gen_fsm 行为 (stdlib v6.2)

已弃用,并在 OTP 20 中被 gen_statem 替代。

迁移到 gen_statem

以下是一个将 gen_fsm 转换为 gen_statem 的简单示例。该示例来自之前的 gen_fsm 用户指南

-module(code_lock).
-define(NAME, code_lock).
%-define(BEFORE_REWRITE, true).

-ifdef(BEFORE_REWRITE).
-behaviour(gen_fsm).
-else.
-behaviour(gen_statem).
-endif.

-export([start_link/1, button/1, stop/0]).

-ifdef(BEFORE_REWRITE).
-export([init/1, locked/2, open/2, handle_sync_event/4, handle_event/3,
     handle_info/3, terminate/3, code_change/4]).
-else.
-export([init/1, callback_mode/0, locked/3, open/3,
     terminate/3, code_change/4]).
%% Add callback__mode/0
%% Change arity of the state functions
%% Remove handle_info/3
-endif.

-ifdef(BEFORE_REWRITE).
start_link(Code) ->
    gen_fsm:start_link({local, ?NAME}, ?MODULE, Code, []).
-else.
start_link(Code) ->
    gen_statem:start_link({local,?NAME}, ?MODULE, Code, []).
-endif.

-ifdef(BEFORE_REWRITE).
button(Digit) ->
    gen_fsm:send_event(?NAME, {button, Digit}).
-else.
button(Digit) ->
    gen_statem:cast(?NAME, {button,Digit}).
    %% send_event is asynchronous and becomes a cast
-endif.

-ifdef(BEFORE_REWRITE).
stop() ->
    gen_fsm:sync_send_all_state_event(?NAME, stop).
-else.
stop() ->
    gen_statem:call(?NAME, stop).
    %% sync_send is synchronous and becomes call
    %% all_state is handled by callback code in gen_statem
-endif.

init(Code) ->
    do_lock(),
    Data = #{code => Code, remaining => Code},
    {ok, locked, Data}.

-ifdef(BEFORE_REWRITE).
-else.
callback_mode() ->
    state_functions.
%% state_functions mode is the mode most similar to
%% gen_fsm. There is also handle_event mode which is
%% a fairly different concept.
-endif.

-ifdef(BEFORE_REWRITE).
locked({button, Digit}, Data0) ->
    case analyze_lock(Digit, Data0) of
    {open = StateName, Data} ->
        {next_state, StateName, Data, 10000};
    {StateName, Data} ->
        {next_state, StateName, Data}
    end.
-else.
locked(cast, {button,Digit}, Data0) ->
    case analyze_lock(Digit, Data0) of
    {open = StateName, Data} ->
        {next_state, StateName, Data, 10000};
    {StateName, Data} ->
        {next_state, StateName, Data}
    end;
locked({call, From}, Msg, Data) ->
    handle_call(From, Msg, Data);
locked({info, Msg}, StateName, Data) ->
    handle_info(Msg, StateName, Data).
%% Arity differs
%% All state events are dispatched to handle_call and handle_info help
%% functions. If you want to handle a call or cast event specifically
%% for this state you would add a special clause for it above.
-endif.

-ifdef(BEFORE_REWRITE).
open(timeout, State) ->
     do_lock(),
    {next_state, locked, State};
open({button,_}, Data) ->
    {next_state, locked, Data}.
-else.
open(timeout, _, Data) ->
    do_lock(),
    {next_state, locked, Data};
open(cast, {button,_}, Data) ->
    {next_state, locked, Data};
open({call, From}, Msg, Data) ->
    handle_call(From, Msg, Data);
open(info, Msg, Data) ->
    handle_info(Msg, open, Data).
%% Arity differs
%% All state events are dispatched to handle_call and handle_info help
%% functions. If you want to handle a call or cast event specifically
%% for this state you would add a special clause for it above.
-endif.

-ifdef(BEFORE_REWRITE).
handle_sync_event(stop, _From, _StateName, Data) ->
    {stop, normal, ok, Data}.

handle_event(Event, StateName, Data) ->
    {stop, {shutdown, {unexpected, Event, StateName}}, Data}.

handle_info(Info, StateName, Data) ->
    {stop, {shutdown, {unexpected, Info, StateName}}, StateName, Data}.
-else.
-endif.

terminate(_Reason, State, _Data) ->
    State =/= locked andalso do_lock(),
    ok.
code_change(_Vsn, State, Data, _Extra) ->
    {ok, State, Data}.

%% Internal functions
-ifdef(BEFORE_REWRITE).
-else.
handle_call(From, stop, Data) ->
     {stop_and_reply, normal,  {reply, From, ok}, Data}.

handle_info(Info, StateName, Data) ->
    {stop, {shutdown, {unexpected, Info, StateName}}, StateName, Data}.
%% These are internal functions for handling all state events
%% and not behaviour callbacks as in gen_fsm
-endif.

analyze_lock(Digit, #{code := Code, remaining := Remaining} = Data) ->
     case Remaining of
         [Digit] ->
         do_unlock(),
         {open,  Data#{remaining := Code}};
         [Digit|Rest] -> % Incomplete
             {locked, Data#{remaining := Rest}};
         _Wrong ->
             {locked, Data#{remaining := Code}}
     end.

do_lock() ->
    io:format("Lock~n", []).
do_unlock() ->
    io:format("Unlock~n", []).

OTP 19 文档

模块

gen_fsm

模块摘要

通用有限状态机行为。

描述

此行为模块提供了一个有限状态机。使用此模块实现的通用有限状态机进程(gen_fsm)具有一组标准的接口函数,并包含跟踪和错误报告的功能。它也适用于 OTP 监控树。有关更多信息,请参阅 OTP 设计原则

gen_fsm 进程假设所有特定部分都位于回调模块中,该模块导出一组预定义的函数。行为函数和回调函数之间的关系如下:

gen_fsm module                    Callback module
--------------                    ---------------
gen_fsm:start
gen_fsm:start_link                -----> Module:init/1

gen_fsm:stop                      -----> Module:terminate/3

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:hibernate/3)。如果服务器预计长时间处于空闲状态,这可能很有用。但是,请谨慎使用此功能,因为休眠意味着至少进行两次垃圾回收(在休眠时和唤醒后不久),并且您不想在每次调用繁忙状态机之间执行此操作。

回调函数

请参阅 回调函数部分,了解要从 gen_fsm 回调模块导出的函数。

状态名称 表示状态机的状态。

状态数据 表示实现状态机的 Erlang 进程的内部状态。

摘要

类型

回复目标。请参阅 reply/2

FSM 名称规范:localglobalvia 已注册。

FSM 引用 pid/0 或已注册的 fsm_name/0

回调:已弃用

在升级/降级期间更新内部状态数据

format_status/2 已弃用

可选函数,用于提供描述当前 gen_fsm 进程状态的术语。

处理异步事件。

处理传入的消息

init(Args) 已弃用

初始化进程和内部状态名称状态数据

处理异步事件。

处理同步事件。

在终止前清理。

函数

取消通用 FSM 中的内部计时器。

进入 gen_fsm 接收循环。

enter_loop/5 已弃用

进入 gen_fsm 接收循环。

向调用者发送回复。

异步向通用 FSM 发送事件。

异步向通用 FSM 发送事件。

在通用 FSM 中内部发送延迟事件。

创建一个独立的 gen_fsm 进程,未注册。

创建一个独立的 gen_fsm 进程。

在监控树中创建一个 gen_fsm 进程,未注册。

在监控树中创建一个 gen_fsm 进程。

在通用 FSM 中内部发送超时事件。

同步停止通用 FSM。

同步向通用 FSM 发送事件。

同步向通用 FSM 发送事件。

类型

链接到此类型

enter_loop_opt()

查看源代码 (未导出)
-type enter_loop_opt() :: {debug, Dbgs :: [sys:debug_option()]}.

enter_loop/4,5,6start/3,4start_link/3,4 函数的启动选项

请参阅 start_link/4

-type from() :: {To :: pid(), Tag :: term()}.

回复目标。请参阅 reply/2

链接到此类型

fsm_name()

查看源代码 (未导出)
-type fsm_name() ::
          {local, LocalName :: atom()} |
          {global, GlobalName :: term()} |
          {via, RegMod :: module(), ViaName :: term()}.

FSM 名称规范:localglobalvia 已注册。

在启动 gen_fsm 时使用。请参阅 start_link/4

链接到此类型

fsm_ref()

查看源代码 (未导出)
-type fsm_ref() ::
          pid() |
          (LocalName :: atom()) |
          {Name :: atom(), Node :: atom()} |
          {global, GlobalName :: term()} |
          {via, RegMod :: module(), ViaName :: term()}.

FSM 引用 pid/0 或已注册的 fsm_name/0

例如,在 send_event/2 中使用以指定服务器。

链接到此类型

start_opt()

查看源代码 (未导出)
-type start_opt() ::
          {timeout, Time :: timeout()} | {spawn_opt, [proc_lib:start_spawn_option()]} | enter_loop_opt().

start/3,4start_link/3,4 函数的启动选项

请参阅 start_link/4

回调:已弃用

链接到此回调

code_change(OldVsn, StateName, StateData, Extra)

查看源代码 (可选)
此回调已弃用。回调 gen_fsm:code_change(_,_,_,_) 已弃用;请改用 'gen_statem' 模块。
-callback code_change(OldVsn, StateName, StateData, Extra) -> {ok, NextStateName, NewStateData}
                         when
                             OldVsn :: Vsn | {down, Vsn},
                             Vsn :: term(),
                             StateName :: atom(),
                             NextStateName :: atom(),
                             StateData :: term(),
                             NewStateData :: term(),
                             Extra :: term().

在升级/降级期间更新内部状态数据

gen_fsm 进程在发布升级/降级期间要更新其内部状态数据时,会调用此函数,即当 appup 文件中给出的指令为 {update, Module, Change, ...},其中 Change = {advanced, Extra} 时;请参阅 OTP 设计原则中的发布处理指令部分。OTP 设计原则

对于升级,OldVsnVsn;对于降级,OldVsn{down, Vsn}Vsn 由旧版本回调模块 Module 的 vsn 属性定义。如果没有定义这样的属性,则版本是 Beam 文件的校验和。

StateName 是当前的状态名称StateDatagen_fsm 进程的内部状态数据

Extra 从更新指令的 {advanced, Extra} 部分“按原样”传递。

该函数应返回新的当前状态名称和更新的内部数据。

链接到此回调

format_status/2

查看源代码 (可选)
此回调已弃用。回调 gen_fsm:format_status(_,_) 已弃用;请改用 'gen_statem' 模块。
-callback format_status(Opt, nonempty_improper_list(PDict, [StateData])) -> Status
                           when
                               Opt :: normal | terminate,
                               PDict :: [{Key :: term(), Value :: term()}],
                               StateData :: term(),
                               Status :: term().

可选函数,用于提供描述当前 gen_fsm 进程状态的术语。

第二个参数是 [PDict, StateData],即一个包含 2 个元素的列表,按此顺序排列。

注意

此回调是可选的,因此回调模块不需要导出它。gen_fsm 模块提供了此函数的默认实现,该函数返回回调模块的 状态数据

在以下情况下,gen_fsm 进程会调用此函数

  • 调用 sys:get_status/1,2 之一以获取 gen_fsm 状态。在这种情况下,Opt 设置为原子 normal
  • gen_fsm 进程异常终止并记录错误。在这种情况下,Opt 设置为原子 terminate。

此函数对于更改这些情况下 gen_fsm 状态的形式和外观很有用。希望更改 sys:get_status/1,2 返回值以及其状态在终止错误日志中显示方式的回调模块,会导出 format_status/2 的实例,该实例返回一个描述 gen_fsm 进程当前状态的术语。

PDictgen_fsm 进程的进程字典的当前值。

StateDatagen_fsm 进程的内部状态数据

该函数应返回 Status,一个更改 gen_fsm 进程当前状态和状态详细信息的术语。Status 可以采用的形式没有限制,但对于 sys:get_status/1,2 情况(当 Optnormal 时),Status 值的推荐形式为 [{data, [{"StateData", Term}]}],其中 Term 提供 gen_fsm 状态数据 的相关详细信息。遵循此建议不是必需的,但这会使回调模块状态与 sys:get_status/1,2 返回值的其余部分保持一致。

此函数的一个用途是返回紧凑的替代 状态数据 表示形式,以避免在日志文件中打印大型状态术语。

链接到此回调

handle_event(Event, StateName, StateData)

查看源代码
此回调已弃用。回调 gen_fsm:handle_event(_,_,_) 已弃用;请改用 'gen_statem' 模块。
-callback handle_event(Event, StateName, StateData) -> Result
                          when
                              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 :: timeout(),
                              Reason :: term().

处理异步事件。

每当 gen_fsm 进程收到使用 send_all_state_event/2 发送的事件时,都会调用此函数来处理该事件。

StateNamegen_fsm 进程的当前状态名称

有关其他参数和可能的返回值的说明,请参阅 Module:StateName/2

链接到此回调

handle_info(Info, StateName, StateData)

查看源代码 (可选)
此回调已弃用。回调 gen_fsm:handle_info(_,_,_) 已弃用;请改用 'gen_statem' 模块。
-callback handle_info(Info, StateName, StateData) -> Result
                         when
                             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 :: timeout(),
                             Reason :: normal | term().

处理传入的消息

gen_fsm 进程收到任何其他消息而不是同步或异步事件(或系统消息)时,会调用此函数。

Info 是收到的消息。

有关其他参数和可能的返回值的说明,请参阅 Module:StateName/2

链接到此回调

handle_sync_event(Event, From, StateName, StateData)

查看源代码
此回调已弃用。回调 gen_fsm:handle_sync_event(_,_,_,_) 已弃用;请改用 'gen_statem' 模块。
-callback handle_sync_event(Event, From, StateName, StateData) -> Result
                               when
                                   Event :: term(),
                                   From :: from(),
                                   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 :: timeout(),
                                   Reason :: term().

处理同步事件。

每当 gen_fsm 进程收到使用 sync_send_all_state_event/2,3 发送的事件时,都会调用此函数来处理该事件。

StateNamegen_fsm 进程的当前状态名称

有关其他参数和可能的返回值的说明,请参阅 Module:StateName/3

此回调已弃用。回调 gen_fsm:init(_) 已弃用;请改用 'gen_statem' 模块。
-callback init(Args) -> Result
                  when
                      Args :: term(),
                      Result ::
                          {ok, StateName, StateData} |
                          {ok, StateName, StateData, Timeout} |
                          {ok, StateName, StateData, hibernate} |
                          {stop, Reason} |
                          ignore,
                      StateName :: atom(),
                      StateData :: term(),
                      Timeout :: timeout(),
                      Reason :: term().

初始化进程和内部状态名称状态数据

每当使用 start/3,4start_link/3,4 启动 gen_fsm 进程时,新进程会调用此函数进行初始化。

Args 是提供给 start 函数的 Args 参数。

如果初始化成功,该函数应返回 {ok, StateName, StateData}、{ok, StateName, StateData, Timeout} 或 {ok, StateName, StateData, hibernate},其中 StateName 是初始状态名称StateDatagen_fsm 进程的初始状态数据

如果提供了 integer/0 超时值,则除非在 Timeout 毫秒内收到事件或消息,否则会发生超时。超时由原子 timeout 表示,应由 Module:StateName/2 回调函数处理。原子 infinity 可用于无限期等待,这是默认值。

如果指定 hibernate 而不是超时值,则进程在等待下一个消息到达时进入休眠状态(通过调用 proc_lib:hibernate/3)。

如果初始化失败,该函数返回 {stop, Reason},其中 Reason 是任何术语,或 ignore

链接到此回调

'StateName'(Event, StateData)

查看源代码 (可选)
此回调已弃用。回调 gen_fsm:'StateName'(_,_) 已弃用;请改用 'gen_statem' 模块。
-callback 'StateName'(Event, StateData) -> Result
                         when
                             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 :: timeout(),
                             Reason :: term().

处理异步事件。

对于每个可能的状态名称,都应有一个此函数的实例。每当 gen_fsm 进程收到使用 send_event/2 发送的事件时,都会调用此函数的实例,该实例的名称与当前状态名称 StateName 相同,以处理该事件。如果发生超时,也会调用此函数。

如果发生超时,Event 为原子 timeout,否则为提供给 send_event/2Event 参数。

StateDatagen_fsm 进程的状态数据

如果该函数返回 {next_state, NextStateName, NewStateData}, {next_state, NextStateName, NewStateData, Timeout}, 或 {next_state, NextStateName, NewStateData, hibernate}, 则gen_fsm进程将继续执行,当前[*状态名称*](#state-name) 设置为NextStateName,并可能使用更新的[*状态数据*](#state-data)NewStateData。有关Timeouthibernate的说明,请参阅 [Module:init/1](c:init/1)。如果该函数返回{stop ,Reason, NewStateData}, 则 gen_fsm 进程会调用 Module:terminate(Reason, StateName, NewStateData) 并终止。

链接到此回调

'StateName'(Event, From, StateData)

查看源代码 (可选)
此回调已弃用。回调 gen_fsm:'StateName'(_,_,_) 已弃用;请改用 'gen_statem' 模块。
-callback 'StateName'(Event, From, StateData) -> Result
                         when
                             Event :: term(),
                             From :: from(),
                             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 :: timeout(),
                             Reason :: normal | term().

处理同步事件。

对于每个可能的状态名称,都应该有一个此函数的实例。每当 gen_fsm 进程收到使用 sync_send_event/2,3 发送的事件时,将调用与当前状态名称 StateName 同名的函数实例来处理该事件。

Event 是提供给 sync_send_event/2,3Event 参数。

From 是一个元组 {Pid, Tag},其中 Pid 是调用 sync_send_event/2,3 的进程的 pid/0Tag 是一个唯一的标签。

StateDatagen_fsm 进程的状态数据

  • 如果返回 {reply, Reply, NextStateName, NewStateData}{reply, Reply, NextStateName, NewStateData, Timeout}{reply, Reply, NextStateName, NewStateData, hibernate},则 Reply 会作为 sync_send_event/2,3 的返回值返回给 Fromgen_fsm 进程然后继续执行,并将当前状态名称设置为 NextStateName,并使用可能更新的状态数据 NewStateData。有关 Timeouthibernate 的描述,请参见 Module:init/1

  • 如果返回 {next_state, NextStateName, NewStateData}{next_state, NextStateName, NewStateData, Timeout}{next_state, NextStateName, NewStateData, hibernate},则 gen_fsm 进程将继续在 NextStateName 中使用 NewStateData 执行。必须使用 reply/2 显式指定对 From 的任何回复。

  • 如果函数返回 {stop, Reason, Reply, NewStateData},则 Reply 会返回给 From。如果函数返回 {stop, Reason, NewStateData},则必须使用 reply/2 显式指定对 From 的任何回复。gen_fsm 进程然后调用 Module:terminate(Reason, StateName, NewStateData) 并终止。

链接到此回调

terminate(Reason, StateName, StateData)

查看源代码 (可选)
此回调已弃用。回调 gen_fsm:terminate(_,_,_) 已弃用;请改用 'gen_statem' 模块。
-callback terminate(Reason, StateName, StateData) -> _
                       when
                           Reason :: normal | shutdown | {shutdown, term()} | term(),
                           StateName :: atom(),
                           StateData :: term().

在终止前清理。

此函数由 gen_fsm 进程在其即将终止时调用。它应该与 Module:init/1 相反,并执行任何必要的清理工作。当它返回时,gen_fsm 进程将以 Reason 终止。返回值将被忽略。

Reason 是表示停止原因的术语,StateName 是当前状态名称StateDatagen_fsm 进程的状态数据

Reason 取决于 gen_fsm 进程终止的原因。如果是因为另一个回调函数返回了一个停止元组 {stop, ...},则 Reason 的值是该元组中指定的值。如果是因为故障,则 Reason 是错误原因。

如果 gen_fsm 进程是监控树的一部分,并且其监控者命令其终止,则如果满足以下条件,将使用 Reason = shutdown 调用此函数

  • 已将 gen_fsm 进程设置为捕获退出信号。

  • 监控者的子规范中定义的关闭策略是一个整数超时值,而不是 brutal_kill。

即使 gen_fsm 进程是监控树的一部分,如果它收到来自其父进程的 'EXIT' 消息,也会调用此函数。Reason'EXIT' 消息中的相同。

否则,gen_fsm 进程会立即终止。

请注意,对于除 normalshutdown{shutdown, Term} 以外的任何其他原因,都假定 gen_fsm 进程因错误而终止,并且会使用 error_logger:format/2 发出错误报告。

函数

此函数已弃用。gen_fsm:cancel_timer/1 已弃用;请改用 'gen_statem' 模块。
-spec cancel_timer(Ref) -> RemainingTime | false
                      when Ref :: reference(), RemainingTime :: non_neg_integer().

取消通用 FSM 中的内部计时器。

取消调用此函数的 gen_fsm 进程中由 Ref 引用的内部计时器。

Ref 是从 send_event_after/2start_timer/2 返回的引用。

如果计时器已超时,但事件尚未传递,则会像未超时一样取消它,因此从此函数返回后不会出现错误的计时器事件。

返回计时器如果 Ref 引用的是活动计时器,则计时器将在超时之前剩余的毫秒数;否则返回 false

链接到此函数

enter_loop(Module, Options, StateName, StateData)

查看源代码
此函数已弃用。gen_fsm:enter_loop/4 已弃用;请改用 'gen_statem' 模块。
-spec enter_loop(Module, Options, StateName, StateData) -> no_return()
                    when
                        Module :: module(),
                        Options :: [enter_loop_opt()],
                        StateName :: atom(),
                        StateData :: term().

进入 gen_fsm 接收循环。

等效于 enter_loop/6,其中 Timeout = infinity,但启动的服务器未像 start_link/3 那样注册。

此函数已弃用。gen_fsm:enter_loop/5 已弃用;请改用 'gen_statem' 模块。
-spec enter_loop(Module, Options, StateName, StateData, FsmName) -> no_return()
                    when
                        Module :: module(),
                        Options :: [enter_loop_opt()],
                        StateName :: atom(),
                        StateData :: term(),
                        FsmName :: fsm_name();
                (Module, Options, StateName, StateData, Timeout) -> no_return()
                    when
                        Module :: module(),
                        Options :: enter_loop_opt(),
                        StateName :: atom(),
                        StateData :: term(),
                        Timeout :: timeout().

进入 gen_fsm 接收循环。

使用参数 FsmName 等效于 enter_loop/6,其中 Timeout = infinity

使用参数 Timeout 等效于 enter_loop/6,但启动的服务器未像 start_link/3 那样注册。

链接到此函数

enter_loop(Module, Options, StateName, StateData, FsmName, Timeout)

查看源代码
此函数已弃用。gen_fsm:enter_loop/6 已弃用;请改用 'gen_statem' 模块。
-spec enter_loop(Module, Options, StateName, StateData, FsmName, Timeout) -> no_return()
                    when
                        Module :: module(),
                        Options :: [enter_loop_opt()],
                        StateName :: atom(),
                        StateData :: term(),
                        FsmName :: fsm_name() | pid(),
                        Timeout :: timeout().

进入 gen_fsm 接收循环。

将现有进程转换为 gen_fsm 进程。不返回,而是调用进程进入 gen_fsm 接收循环并成为 gen_fsm 进程。必须使用 proc_lib 中的 start 函数之一启动该进程。用户负责进程的任何初始化,包括为其注册名称。

当需要比 gen_fsm 行为提供的更复杂的初始化过程时,此函数非常有用。

ModuleOptionsFsmName 与调用 start[_link]/3,4 时的含义相同。但是,必须在调用此函数之前根据 FsmName 注册该进程。

StateNameStateDataTimeoutModule:init/1 的返回值中的含义相同。回调模块 Module 不需要导出 init/1 函数。

如果调用进程不是由 proc_lib start 函数启动的,或者如果未根据 FsmName 注册,则该函数将失败。

此函数已弃用。gen_fsm:reply/2 已弃用;请改用 'gen_statem' 模块。
-spec reply(Caller, Reply) -> Result when Caller :: from(), Reply :: term(), Result :: term().

向调用者发送回复。

当回复无法在 Module:StateName/3Module:handle_sync_event/4 的返回值中定义时,gen_fsm 进程可以使用此函数显式向调用 sync_send_event/2,3sync_send_all_state_event/2,3 的客户端进程发送回复。

Caller 必须是提供给回调函数的 From 参数。Reply 是作为 sync_send_event/2,3sync_send_all_state_event/2,3 的返回值返回给客户端的任何术语。

返回值 Result 未进一步定义,并且始终会被忽略。

链接到此函数

send_all_state_event(FsmRef, Event)

查看源代码
此函数已弃用。gen_fsm:send_all_state_event/2 已弃用;请改用 'gen_statem' 模块。
-spec send_all_state_event(FsmRef, Event) -> ok when FsmRef :: fsm_ref(), Event :: term().

异步向通用 FSM 发送事件。

将事件异步发送到 gen_fsm 进程的 FsmRef,并立即返回 okgen_fsm 进程调用 Module:handle_event/3 来处理该事件。

有关参数的描述,请参见 send_event/2

send_event/2send_all_state_event/2 之间的区别在于使用哪个回调函数来处理事件。当发送在每个状态下以相同方式处理的事件时,此函数很有用,因为只需要一个 handle_event 子句来处理事件,而无需在每个状态名称函数中都使用一个子句。

链接到此函数

send_event(FsmRef, Event)

查看源代码
此函数已弃用。gen_fsm:send_event/2 已弃用;请改用 'gen_statem' 模块。
-spec send_event(FsmRef, Event) -> ok when FsmRef :: fsm_ref(), Event :: term().

异步向通用 FSM 发送事件。

Event 发送到 gen_fsm 进程的 FsmRef,并立即返回 okgen_fsm 进程调用 Module:StateName/2 来处理该事件,其中 StateNamegen_fsm 进程的当前状态的名称。

FsmRef 可以是以下任何一种

  • pid/0
  • Name,如果 gen_fsm 进程已在本地注册
  • {Name, Node},如果 gen_fsm 进程已在另一个节点本地注册
  • {global, GlobalName},如果 gen_fsm 进程已全局注册
  • {via, Module, ViaName},如果 gen_fsm 进程是通过备用进程注册表注册的

Event 是作为 Module:StateName/2 的参数之一传递的任何术语。

链接到此函数

send_event_after(Time, Event)

查看源代码
此函数已弃用。gen_fsm:send_event_after/2 已弃用;请改用 'gen_statem' 模块。
-spec send_event_after(Time, Event) -> Ref
                          when Time :: non_neg_integer(), Event :: term(), Ref :: reference().

在通用 FSM 中内部发送延迟事件。

在调用此函数的 gen_fsm 进程内部延迟发送事件,延迟时间为 Time 毫秒。立即返回一个引用,该引用可用于使用 cancel_timer/1 取消延迟发送。

gen_fsm 进程调用 Module:StateName/2 来处理该事件,其中 'StateName' 是传递延迟事件时 gen_fsm 进程的当前状态的名称。

Event 是作为 Module:StateName/2 的参数之一传递的任何术语。

链接到此函数

start(Module, Args, Options)

查看源代码
此函数已弃用。gen_fsm:start/3 已弃用;请改用 'gen_statem' 模块。
-spec start(Module, Args, Options) -> Result
               when
                   Module :: module(),
                   Args :: term(),
                   Options :: [start_opt()],
                   Result :: {ok, Pid} | ignore | {error, Reason},
                   Pid :: pid(),
                   Reason :: term().

创建一个独立的 gen_fsm 进程,未注册。

等效于 start(Name, Mod, Args, Options),但不注册 Name

有关参数和返回值的说明,请参阅 start_link/3,4

链接到此函数

start(FsmName, Module, Args, Options)

查看源代码
此函数已弃用。gen_fsm:start/4 已弃用;请改用 'gen_statem' 模块。
-spec start(FsmName, Module, Args, Options) -> Result
               when
                   FsmName :: fsm_name(),
                   Module :: module(),
                   Args :: term(),
                   Options :: [start_opt()],
                   Result :: {ok, Pid} | ignore | {error, Reason},
                   Pid :: pid(),
                   Reason :: {already_started, Pid} | term().

创建一个独立的 gen_fsm 进程。

创建的进程不属于监督树,因此没有监督者。

有关参数和返回值的说明,请参阅 start_link/3,4

链接到此函数

start_link(Module, Args, Options)

查看源代码
此函数已弃用。gen_fsm:start_link/3 已弃用;请改用 'gen_statem' 模块。
-spec start_link(Module, Args, Options) -> Result
                    when
                        Module :: module(),
                        Args :: term(),
                        Options :: [start_opt()],
                        Result :: {ok, Pid} | ignore | {error, Reason},
                        Pid :: pid(),
                        Reason :: term().

在监控树中创建一个 gen_fsm 进程,未注册。

等效于 start_link(Name, Mod, Args, Options),但不注册 Name

链接到此函数

start_link(FsmName, Module, Args, Options)

查看源代码
此函数已弃用。gen_fsm:start_link/4 已弃用;请改用 'gen_statem' 模块。
-spec start_link(FsmName, Module, Args, Options) -> Result
                    when
                        FsmName :: fsm_name(),
                        Module :: module(),
                        Args :: term(),
                        Options :: [start_opt()],
                        Result :: {ok, Pid} | ignore | {error, Reason},
                        Pid :: pid(),
                        Reason :: {already_started, Pid} | term().

在监控树中创建一个 gen_fsm 进程。

该进程作为监督树的一部分创建。此函数应由监督者直接或间接调用。例如,它确保 gen_fsm 进程链接到监督者。

gen_fsm 进程调用 Module:init/1 进行初始化。为了确保同步的启动过程,start_link/3,4Module:init/1 返回之前不会返回。

  • 如果 FsmName = {local, Name},则 gen_fsm 进程使用 register/2 在本地注册为 Name

  • 如果 FsmName = {global, GlobalName},则 gen_fsm 进程使用 global:register_name/2 在全局注册为 GlobalName

  • 如果 FsmName = {via, Module, ViaName},则 gen_fsm 进程向由 Module 表示的注册表注册。Module 回调应导出函数 register_name/2unregister_name/1whereis_name/1send/2,这些函数的行为应类似于 global 中的相应函数。因此,{via, global, GlobalName} 是一个有效的引用。

Module 是回调模块的名称。

Args 是任何作为参数传递给 Module:init/1 的项。

如果存在选项 {timeout, Time},则允许 gen_fsm 进程花费 Time 毫秒进行初始化,否则它会终止并且启动函数返回 {error, timeout}

如果存在选项 {debug, Dbgs},则为 Dbgs 中的每个项目调用相应的 sys 函数;请参阅 sys(3)

如果存在选项 {spawn_opt, SOpts},则 SOpts 作为选项列表传递给用于生成 gen_fsm 进程的 spawn_opt BIF;请参阅 spawn_opt/2

注意

不允许使用生成选项 monitor,它会导致函数因 badarg 原因而失败。

如果成功创建并初始化了 gen_fsm 进程,则该函数返回 {ok, Pid},其中 Pidgen_fsm 进程的 pid。如果具有指定 FsmName 的进程已存在,则该函数返回 {error, {already_started, Pid}},其中 Pid 是该进程的 pid。

如果 Module:init/1Reason 而失败,则该函数返回 {error, Reason}。如果 Module:init/1 返回 {stop, Reason}ignore,则进程将终止,并且该函数分别返回 {error, Reason}ignore

链接到此函数

start_timer(Time, Msg)

查看源代码
此函数已弃用。gen_fsm:start_timer/2 已弃用;请改用 'gen_statem' 模块。
-spec start_timer(Time, Msg) -> Ref when Time :: non_neg_integer(), Msg :: term(), Ref :: reference().

在通用 FSM 中内部发送超时事件。

Time 毫秒后,在调用此函数的 gen_fsm 进程中内部发送超时事件。立即返回一个引用,该引用可用于使用 cancel_timer/1 取消计时器。

gen_fsm 进程调用 Module:StateName/2 来处理该事件,其中 'StateName' 是在传递超时消息时 gen_fsm 进程的当前状态的名称。

Msg 是在超时消息 {timeout, Ref, Msg} 中传递的任何项,作为 Module:StateName/2 的参数之一。

此函数已弃用。gen_fsm:stop/1 已弃用;请改用 'gen_statem' 模块。
-spec stop(FsmRef) -> ok when FsmRef :: fsm_ref().

等效于 stop(FsmRef, normal, infinity)

链接到此函数

stop(FsmRef, Reason, Timeout)

查看源代码
此函数已弃用。gen_fsm:stop/3 已弃用;请改用 'gen_statem' 模块。
-spec stop(FsmRef, Reason, Timeout) -> ok
              when FsmRef :: fsm_ref(), Reason :: term(), Timeout :: timeout().

同步停止通用 FSM。

命令一个通用有限状态机以指定的 Reason 退出,并等待其终止。gen_fsm 进程在退出之前调用 Module:terminate/3

如果通用有限状态机以预期的原因终止,则该函数返回 ok。除了 normalshutdown{shutdown, Term} 之外的任何其他原因都会导致使用 error_logger:format/2 发出错误报告。

Timeout 是一个大于零的整数,用于指定等待通用 FSM 终止的毫秒数,或者是原子 infinity 表示无限期等待。如果通用有限状态机在指定时间内未终止,则会引发 timeout 异常。

如果该进程不存在,则会引发 noproc 异常。

链接到此函数

sync_send_all_state_event(FsmRef, Event)

查看源代码
此函数已弃用。gen_fsm:sync_send_all_state_event/2 已弃用;请改用 'gen_statem' 模块。
-spec sync_send_all_state_event(FsmRef, Event) -> Reply
                                   when FsmRef :: fsm_ref(), Event :: term, Reply :: term().

等效于 sync_send_all_state_event(FsmRef, Event, 5000)

链接到此函数

sync_send_all_state_event(FsmRef, Event, Timeout)

查看源代码
此函数已弃用。gen_fsm:sync_send_all_state_event/3 已弃用;请改用 'gen_statem' 模块。
-spec sync_send_all_state_event(FsmRef, Event, Timeout) -> Reply
                                   when
                                       FsmRef :: fsm_ref(),
                                       Event :: term(),
                                       Timeout :: timeout(),
                                       Reply :: term().

同步向通用 FSM 发送事件。

gen_fsm 进程的 FsmRef 发送一个事件,并等待直到收到回复或发生超时。gen_fsm 进程调用 Module:handle_sync_event/4 来处理该事件。

有关 FsmRefEvent 的说明,请参阅 send_event/2。有关 TimeoutReply 的说明,请参阅 sync_send_event/3

有关 sync_send_eventsync_send_all_state_event 之间差异的讨论,请参阅 send_all_state_event/2

链接到此函数

sync_send_event(FsmRef, Event)

查看源代码
此函数已弃用。gen_fsm:sync_send_event/2 已弃用;请改用 'gen_statem' 模块。
-spec sync_send_event(FsmRef, Event) -> Reply when FsmRef :: fsm_ref(), Event :: term(), Reply :: term().

等效于 sync_send_event(FsmRef, Event, 5000)

链接到此函数

sync_send_event(FsmRef, Event, Timeout)

查看源代码
此函数已弃用。gen_fsm:sync_send_event/3 已弃用;请改用 'gen_statem' 模块。
-spec sync_send_event(FsmRef, Event, Timeout) -> Reply
                         when
                             FsmRef :: fsm_ref(), Event :: term(), Timeout :: timeout(), Reply :: term().

同步向通用 FSM 发送事件。

gen_fsm 进程的 FsmRef 发送一个事件,并等待直到收到回复或发生超时。gen_fsm 进程调用 Module:StateName/3 来处理该事件,其中 'StateName'gen_fsm 进程当前状态的名称。

有关 FsmRefEvent 的说明,请参阅 send_event/2

Timeout 是一个大于零的整数,用于指定等待回复的毫秒数,或者是原子 infinity 表示无限期等待。如果在指定时间内未收到回复,则函数调用失败。

返回值 ReplyModule:StateName/3 的返回值中定义。

注意

如果服务器在调用期间死亡并且链接到客户端,则有时会消耗服务器退出消息的旧行为已在 Erlang 5.6/OTP R12B 中删除。