关于erlang提供的gen_fsm有限状态机模型,可以说是很好很强大,正是有了它,才使erlang编写复杂业务逻辑成为一件轻松愉快的事情
但是由于erlang的速错设计原则,我们的状态机进程可能在某些异常下直接退出,这点可能跟我们的需要有点背离
最常见的情况是,状态转移中的错误处理问题,如下代码:
%% ====================================================================
%% Interface Function
%% ====================================================================
join(UserId)->
io:format("join UserId=~p~n",[UserId]),
gen_fsm:sync_send_event(?MODULE, {join,UserId}).
start()->
gen_fsm:send_event(?MODULE,start).
%% ====================================================================
%% Callback Function
%% ====================================================================
wait_player({join,UserId},_From, State) ->
Count=State#state.count+1,
if
Count =:= 3 ->
io:format("jump to next phrase -> start~n"),
{reply,next_phrase,wait_start,State};
true->
NewState=State#state{count=Count},
{reply,stand_still,wait_player,NewState}
end.
wait_start(start,State)->
io:format("recv start event ~n"),
{next_state,wait_start,State}.
start_link()->
gen_fsm:start_link({local,?MODULE}, ?MODULE, [] ,[]).
init([])->
{ok, wait_player, #state{count=0}}.
我要实现的是一个简单的状态转移,
初始状态是 wait_player,收到 {join,UserId} 的消息后,进行简单业务逻辑处理判断,当有3个人加入进来,则转移到下一状态 wait_start,这时的StateName是 wait_start,
但是,假如这时客户端继续调用了join接口,也就是发送了{join,UserId}的消息给gen_fsm进程,那么gen_fsm实际回调的是 Mod:StateName,
也就是我们的wait_start({join,UserId},State)方法,结果就是undef 错误,然后整个gen_fsm进程退出,这就不是我想要的了,我希望我的gen_fsm进程能够不理会这种错误的消息或行为(只记录下错误调用日志即可),而不是直接退出
再来简单看一下gen_fsm处理流程(其实基本和gen_server差不多的),
gen_fsm进程启动后会进入一个main loop,等待处理mailbox里的消息,根据消息类型(接口处打上不同的label)分类处理,回调等
main_loop 代码
loop(Parent, Name, StateName, StateData, Mod, Time, Debug) ->
Msg = receive
Input ->
Input
after Time ->
{'$gen_event', timeout}
end,
decode_msg(Msg,Parent, Name, StateName, StateData, Mod, Time, Debug, false).
跟踪到这里
handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time) -> %No debug here
From = from(Msg),
case catch dispatch(Msg, Mod, StateName, StateData) of
{next_state, NStateName, NStateData} ->
loop(Parent, Name, NStateName, NStateData, Mod, infinity, []);
{next_state, NStateName, NStateData, Time1} ->
loop(Parent, Name, NStateName, NStateData, Mod, Time1, []);
{reply, Reply, NStateName, NStateData} when From =/= undefined ->
reply(From, Reply),
loop(Parent, Name, NStateName, NStateData, Mod, infinity, []);
{reply, Reply, NStateName, NStateData, Time1} when From =/= undefined ->
reply(From, Reply),
loop(Parent, Name, NStateName, NStateData, Mod, Time1, []);
{stop, Reason, NStateData} ->
terminate(Reason, Name, Msg, Mod, StateName, NStateData, []);
{stop, Reason, Reply, NStateData} when From =/= undefined ->
{'EXIT', R} = (catch terminate(Reason, Name, Msg, Mod,
StateName, NStateData, [])),
reply(From, Reply),
exit(R);
{'EXIT', What} ->
%%{Reason,StackInfo}=What,
%%loop(Parent, Name, StateName, StateData, Mod, infinity, []);
terminate(What, Name, Msg, Mod, StateName, StateData, []);
Reply ->
terminate({bad_return_value, Reply},
Name, Msg, Mod, StateName, StateData, [])
end.
dispatch函数实际就是根据消息label,调用不同回调接口的地方,然后可以看到,根据回调接口的返回,来进行不同处理,
异步的消息直接返回{next_state,...},
同步则是{reply,...}
其实最重要的是告知gen_fsm的下一状态名,也就是NStateName
实际,消息回调发生问题,或者错误的状态消息,则会返回{'EXIT',What}这个消息,gen_fsm源码是一律 terminate
我添加了2行注释,可以不直接退出
%%{Reason,StackInfo}=What,
%%loop(Parent, Name, StateName, StateData, Mod, infinity, []);
实际我们要做的就是在这个基础上完善一下就可以了,比如可以根据Reason判断那种情况该terminate,那种情况可以忽略,继续loop进入主循环处理下一消息
另外一个注意的问题是,尽管加了这2行代码后,gen_fsm不会立即由于undef function而直接退出,但是由于我们的join接口是sync同步调用,实际在gen.erl里会等待gen_fsm进程处理完该消息的返回,
而实际由于是一个错误的调用,所以我们可以返回一个自定义的错误,或者干脆不理会这个返回,如果不理会,则gen.erl由于等待消息超时一样会crash,实际crash的是调用者进程,所以要做好catch
这样,通过添加2行代码到gen_fsm就可以使我们的gen_fsm进程更稳定了
时间仓促,没有多考虑,应该会有更好的办法
分享到:
相关推荐
在压缩包内的“FSM”文件,可能是该模板的源代码或详细说明文档,用于指导开发者如何构建和使用这个三段式状态机。如果这是一个代码文件,可能包含了状态的枚举定义、事件处理函数以及状态转换的逻辑代码。如果是...
有限状态机(FSM)是一种数学模型,它具有有限数量的状态,这些状态之间通过事件(或输入)相互转换。在8051实现中,这些状态通常由变量表示,而状态转换则通过条件语句(如if-else)或switch-case结构来实现。 "_...
状态机(Finite State Machine, FSM)是数字系统设计中的核心概念,特别是在Verilog这样的硬件描述语言中,状态机被广泛用于实现控制逻辑。本资源"FSM.rar"提供了一种详细的学习材料,专注于不同类型的Verilog状态机...
在编程领域,有限状态机(FSM,Finite State Machine)是一种设计模式,它根据当前状态和输入来决定系统的行为。在本项目"FSM.rar"中,开发者利用FSM来控制飞船的行为,模拟了类似小行星游戏中的飞船控制系统。这个...
在本压缩包文件"AXI_Master_FSM.rar"中,重点是实现了一个基于状态机(Finite State Machine, FSM)的AXI主设备(AXI Master)。 AXI主设备是AXI协议中的一个关键组件,它负责发起数据传输请求,控制读写操作,并...
在数字电路设计中,有限状态机(Finite State Machine, FSM)是一种重要的逻辑设计方法,用于实现具有特定行为的序列逻辑。在Verilog HDL(硬件描述语言)中,我们可以用它来描述和实现复杂的数字系统。本文将深入...
标题中的"fsm_hello_fsm_hello_FSM_"似乎是一个与有限状态机(Finite State Machine,FSM)相关的项目或文件命名约定,其中"hello"可能代表一个示例或特定的模块,而"FSM"是有限状态机的缩写。在描述中,我们只有一...
状态机(Finite State Machine, FSM)是数字系统设计中一种重要的概念,特别是在VHDL这样的硬件描述语言中,它被广泛用于实现各种控制逻辑。在本压缩包“fsm.rar”中,我们可以看到一系列与FSM相关的VHDL代码实例,...
在USB OTG系统中,FSM(Finite State Machine,有限状态机)扮演着关键角色,用于管理OTG设备之间的角色切换和通信流程。`otg_fsm.rar_FSM_otg`这个标题暗示了我们讨论的是关于ChipIdea USB IP核心中的OTG FSM驱动...
在电子设计自动化(EDA)领域,有限状态机(Finite State Machine, FSM)是一种常见的数字逻辑设计方法,广泛应用于各种嵌入式系统、处理器控制单元以及通信协议等。本压缩包"source_file_有限状态机tb_fsm_moore_...
标题中的"**textsearch_fsm.rar_FSM**"表明这是一个与文本搜索相关的有限状态机(Finite State Machine, FSM)项目,而文件"**ts_fsm_token**"则是该机器中用于处理状态转换的关键组件,称为“状态机令牌”。...
视频中工程代码 class8_FSM视频中工程代码 class8_FSM视频中工程代码 class8_FSM视频中工程代码 class8_FSM视频中工程代码 class8_FSM视频中工程代码 class8_FSM视频中工程代码 class8_FSM视频中工程代码 class8_FSM...
标题中的“Stepper_motor_fsm.rar_FSM_FSM vhdl_it_stepper motor”表明这是一个关于步进电机(stepper motor)的文件,其中包含了状态机(Finite State Machine, FSM)的设计,设计语言为VHDL,这通常用于数字逻辑...
Gen_Fsm,即通用有限状态机,是一种行为模式,它提供了一种结构化的方法来处理具有多种状态和事件的系统。本文将深入探讨Gen_Fsm的行为及其在Erlang OTP中的应用。 首先,Gen_Fsm行为的核心是一个有限状态机(FSM)...
有限状态机又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。它反映从系统开始到现在时刻的输入变化,转移指示状态变更,并且用必须满足来确使转移发生的条件来...
通过研究源码,我们可以深入了解如何在实际项目中构建和运用状态机。 此外,压缩包中包含的"泽国社区.url"可能指向一个开发者论坛或者资源分享平台,那里可能有更多关于KGFMapSystem2.3的讨论和扩展资源,为开发者...
**有限状态机(Finite State Machine, FSM)** 有限状态机是一种数学模型,广泛应用于计算机科学、电子工程、自动控制等领域。它通过定义一系列状态以及在这些状态之间转换的规则来描述系统的行为。在这个"FSM_...
通过学习这个小游戏的有限状态机(Finite State Machine, FSM)实现,我们可以更好地理解VHDL语言以及如何用其构建复杂的数字系统。 FSM是电子工程中的基础概念,它能够模拟任何有固定数量状态和转换规则的系统。在...
有限状态机(Finite State Machine, FSM)是一种在数字系统设计中广泛应用的概念,特别是在VHDL(Very High Speed Integrated Circuit Hardware Description Language)编程中。VHDL是一种用于电子设计自动化(EDA)...