OTP学习之 Gen_Fsm

状态机,是在通信领域内用得最多的,在业务平台中也是,数据实体在平台中流动处理,不同状态,需要不同的处理。

关于状态机的描述,Boost文档里面有比较详细的描述,这个博客也有比较清晰的描述:状态机

在C++ boost库中有大名鼎鼎的MSM,自己写的话,看看状态机模式也就可以搞定,Erlang中又是怎么实现的呢?没错就是Gen_fsm了。

有限状态机可以描述为以下关系:

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

在S状态下,E事件发生,我们需要采取A动作,状态变迁为S'基于gen_fsm实现的状态机,由一些列如下代码所示的Erlang函数形成迁移规则:
StateName(Event, StateData) ->
    .. code for actions here ...
    {next_state, StateName', StateData'}

 

一个带密码锁的门可以视为FSM,门最开始是锁着的,任何时候一个人按下按钮,将会产生一个事件。具体事件取决于按下之前按钮的状态,序列可能是正确的、不完整的或者时错误的。

按下,如果错误,我们重头再来,等待一个完整的按键序列。

实现密码锁的FSM Erlang代码如下:

    1. -module(code_lock).  
    2. -behaviour(gen_fsm).  
    3.   
    4. -export([start_link/1]).  
    5. -export([button/1]).  
    6.   
    7. -export([init/1, locked/2, open/2]).  
    8. -export([code_change/4, handle_event/3, handle_info/3, handle_sync_event/4, terminate/3]).  
    9.   
    10. -spec(start_link(Code::string()) -> {ok,pid()} | ignore | {error,term()}).  
    11. start_link(Code) ->  
    12.     gen_fsm:start_link({local, code_lock}, code_lock, Code, []).  
    13.   
    14. -spec(button(Digit::string()) -> ok).  
    15. button(Digit) ->  
    16.     gen_fsm:send_event(code_lock, {button, Digit}).  
    17.   
    18. init(LockCode) ->  
    19.     io:format("init: ~p~n", [LockCode]),  
    20.     {ok, locked, {[], LockCode}}.  
    21.   
    22. locked({button, Digit}, {SoFar, Code}) ->  
    23.     io:format("buttion: ~p, So far: ~p, Code: ~p~n", [Digit, SoFar, Code]),  
    24.     InputDigits = lists:append(SoFar, Digit),  
    25.     case InputDigits of  
    26.         Code ->  
    27.             do_unlock(),  
    28.             {next_state, open, {[], Code}, 10000};  
    29.         Incomplete when length(Incomplete)<length(Code) ->  
    30.             {next_state, locked, {Incomplete, Code}, 5000};  
    31.         Wrong ->  
    32.             io:format("wrong passwd: ~p~n", [Wrong]),  
    33.             {next_state, locked, {[], Code}}  
    34.     end;  
    35. locked(timeout, {_SoFar, Code}) ->  
    36.     io:format("timout when waiting button inputting, clean the input, button again plz~n"),  
    37.     {next_state, locked, {[], Code}}.  
    38.   
    39. open(timeout, State) ->  
    40.     do_lock(),  
    41.     {next_state, locked, State}.  
    42.   
    43. code_change(_OldVsn, StateName, Data, _Extra) ->  
    44.     {ok, StateName, Data}.  
    45.   
    46. terminate(normal, _StateName, _Data) ->  
    47.     ok.  
    48.   
    49. handle_event(Event, StateName, Data) ->  
    50.     io:format("handle_event... ~n"),  
    51.     unexpected(Event, StateName),  
    52.     {next_state, StateName, Data}.  
    53.   
    54. handle_sync_event(Event, From, StateName, Data) ->  
    55.     io:format("handle_sync_event, for process: ~p... ~n", [From]),  
    56.     unexpected(Event, StateName),  
    57.     {next_state, StateName, Data}.  
    58.   
    59. handle_info(Info, StateName, Data) ->  
    60.     io:format("handle_info...~n"),  
    61.     unexpected(Info, StateName),  
    62.     {next_state, StateName, Data}.  
    63.   
    64.   
    65. %% Unexpected allows to log unexpected messages  
    66. unexpected(Msg, State) ->  
    67.     io:format("~p RECEIVED UNKNOWN EVENT: ~p, while FSM process in state: ~p~n",  
    68.               [self(), Msg, State]).  
    69. %%  
    70. %% actions  
    71. do_unlock() ->  
    72.     io:format("passwd is right, open the DOOR.~n").  
    73.   
    74. do_lock() ->  
    75.     io:format("over, close the DOOR.~n").

 

 

posted @ 2014-05-22 10:03  浚宇他爹  阅读(298)  评论(0编辑  收藏  举报