erlang fsm 使用

有限状态机( 问什么从来没有提过无限状态机,请知道的朋友不吝赐教)的官方文档定义是:

State(S) x Event(E) -> Actions(A), State(S')

If we are in state S and the event E occurs, we should perform the actions A and make a transition to        the state S'.

  或者用下面的表理解:

条件/当前状态状态A状态B状态C
条件X.........
条件Y...状态C...
条件Z状态B...状态A

 如何写一个gen_fms呢,下面以例子来讲诉。

 1. 假设一个人有这么3种状态(健康,生病和康复中),以及对应的转换事件(淋雨,治疗和休息)

  2. 定义状态名分别为health,sick和rehabilitationing,事件分别为rain,treatment和一个特殊的timeout。每种状态下,不需要额外的状态数据。

  3. 按照gen_fsm规定,状态转换规则是以状态名同名的回调函数,格式为:

StateName(Event, StateData) ->
    .. code for actions here ...
    {next_state, StateName', StateData'}

  所以在这个例子里,我们写上3个状态处理回调函数:

%% 健康状态下淋雨,变为生病状态
health( rain, StateData ) ->
    { next_state, sick, StateData }.

%% 生病状态下被治疗,进入康复中状态    
sick( treatment, StateData ) ->
    { next_state, rehabilitationing, StateData, 30000  }.      %% 30秒后有timeout事件

%% 康复中状态下,超时事件发生,进入健康状态
rehabilitationing( timeout, StateData ) ->
    { next_state, health, StateData }.

  每个状态处理回调函数的返回值必须是{next_state, 新状态名,新状态对应的状态数据},或者{next_state, 新状态名,新状态对应的状态数据, Timeout时间}。(还可以用{stop, Reason, StateData}作为返回值,来告知gem_fsm进程结束)

  4. 我们还需要一个初始状态,在init回调设置初始状态

init(_Param) ->
  {ok, health, {} }.

  5. 为模块写事件触发API,用gen_fsm:send_event通知gen_fsm事件发生(事件不一定是atom,可以是任意的erlang类型)。

rain() ->
    gen_fsm:send_event( ?MODULE, rain ).

treatment() ->


6. 加上启动API和指定行为模式,我们的gen_fsm例子就算大功告成了。全模块代码如下:

module(person_fsm).
-behaviour(gen_fsm).

-export([start_link/0, init/1]).
-export([rain/0, treatment/0]).
-export([health/2,sick/2,rehabilitationing/2]).

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

init([]) ->
    io:format("initial state is health.~n"),
    {ok, health, {} }.

rain() ->
    gen_fsm:send_event( ?MODULE, rain ).

treatment() ->
    gen_fsm:send_event( ?MODULE, treatment  ).

%% finite state machines
health( rain, {} ) ->
    io:format("turn to state sick.~n"),
    { next_state, sick, {} }.
    
sick( treatment, _StateData ) ->
    io:format("turn to state rehabilitationing.~n"),
    { next_state, rehabilitationing, { }, 30000  }.

rehabilitationing( timeout, _StateData ) ->
    io:format("turn to state health.~n"),
    { next_state, health, {} }.


gen_server和gen_fsm比较:

1. gen_server的状态对应为gen_fsm的一个状态名和状态数据。

2. gen_server在handle_cast里处理异步消息/事件,gen_fsm在状态名同名的回调处理异步事件。

3. gen_fsm实现的例子完全可以用gen_server来实现。


-module(test_fsm).

-export([start_link/0,stand/2,move/2,dead/2,stop/0]).
-export([handle_stand/0,handle_move/0]).

-behaviour(gen_fsm).

%%
-export([init/1,handle_info/3,handle_event/3,handle_sync_event/4,code_change/4,terminate/3]).

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

init([])->
	io:format("init....~n",[]),
	{ok,stand,stand}.

handle_info(_Info,_StateName,_State) ->
	{next_state,_StateName,_State}.
	
handle_event(_Event,StateName,State) ->
	{next_State,StateName,State};
handle_event(stop,StateName,State) ->
	{stop,normal,State}.
	
handle_sync_event(_Event,_From,StateName,State) ->
	Reply = ok,
	{reply,Reply,StateName,State}.
	
code_change(_OldVsn,StateName,State,_Extra) ->
	{ok,StateName,State}.
	
terminate(_Reason,_StateName,_State) ->
	io:format("terminate......~n",[]),
	ok.
	
stand(stand,State) ->
	io:format("stand....~n",[]),
	{next_state,move,State}.
move(move,State) ->
	io:format("move......~n",[]),
	{next_state,dead,State,5000}. %%五秒后将执行死亡
	
dead(timeout,State) ->
	io:format("dead.........~n",[]),
	proc_lib:hibernate(gen_fsm, enter_loop, [?MODULE, [], stand,State]). %%清空stack,重新进入stand
	%%{next_state,stand,State}.

%%==============外部接口函数==============	
handle_stand() ->
	gen_fsm:send_event(?MODULE,stand).
	
handle_move() ->
	gen_fsm:send_event(?MODULE,move).

%%======================stop===
stop() ->
	gen_fsm:send_all_state_event(?MODULE,stop).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值