状态机,是在通信领域内用得最多的,在业务平台中也是,数据实体在平台中流动处理,不同状态,需要不同的处理。
关于状态机的描述,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代码如下:
-
- -module(code_lock).
- -behaviour(gen_fsm).
- -export([start_link/1]).
- -export([button/1]).
- -export([init/1, locked/2, open/2]).
- -export([code_change/4, handle_event/3, handle_info/3, handle_sync_event/4, terminate/3]).
- -spec(start_link(Code::string()) -> {ok,pid()} | ignore | {error,term()}).
- start_link(Code) ->
- gen_fsm:start_link({local, code_lock}, code_lock, Code, []).
- -spec(button(Digit::string()) -> ok).
- button(Digit) ->
- gen_fsm:send_event(code_lock, {button, Digit}).
- init(LockCode) ->
- io:format("init: ~p~n", [LockCode]),
- {ok, locked, {[], LockCode}}.
- locked({button, Digit}, {SoFar, Code}) ->
- io:format("buttion: ~p, So far: ~p, Code: ~p~n", [Digit, SoFar, Code]),
- InputDigits = lists:append(SoFar, Digit),
- case InputDigits of
- Code ->
- do_unlock(),
- {next_state, open, {[], Code}, 10000};
- Incomplete when length(Incomplete)<length(Code) ->
- {next_state, locked, {Incomplete, Code}, 5000};
- Wrong ->
- io:format("wrong passwd: ~p~n", [Wrong]),
- {next_state, locked, {[], Code}}
- end;
- locked(timeout, {_SoFar, Code}) ->
- io:format("timout when waiting button inputting, clean the input, button again plz~n"),
- {next_state, locked, {[], Code}}.
- open(timeout, State) ->
- do_lock(),
- {next_state, locked, State}.
- code_change(_OldVsn, StateName, Data, _Extra) ->
- {ok, StateName, Data}.
- terminate(normal, _StateName, _Data) ->
- ok.
- handle_event(Event, StateName, Data) ->
- io:format("handle_event... ~n"),
- unexpected(Event, StateName),
- {next_state, StateName, Data}.
- handle_sync_event(Event, From, StateName, Data) ->
- io:format("handle_sync_event, for process: ~p... ~n", [From]),
- unexpected(Event, StateName),
- {next_state, StateName, Data}.
- handle_info(Info, StateName, Data) ->
- io:format("handle_info...~n"),
- unexpected(Info, StateName),
- {next_state, StateName, Data}.
- %% Unexpected allows to log unexpected messages
- unexpected(Msg, State) ->
- io:format("~p RECEIVED UNKNOWN EVENT: ~p, while FSM process in state: ~p~n",
- [self(), Msg, State]).
- %%
- %% actions
- do_unlock() ->
- io:format("passwd is right, open the DOOR.~n").
- do_lock() ->
- io:format("over, close the DOOR.~n").