Erlang OTP学习(1)gen_fsm

1. 有限状态机

有限状态机可以用下面这个公式来表达

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

表示的就是在S状态时如果有事件E发生,那么执行动作A后把状态调整到S’。理解很好理解,如果能够熟练应用必须得下苦功,多练习。

start_link跟gen-sever 类似,启动后进入init初始化,结果是 ok,StateName,State. 此例子中是初始化密码门的原始密码,置输入密码为空

2. 一个例子

erlang手册中用这个例子来解释的:开锁问题,有一个密码锁的门,它就可以看作一个状态机,初始状态门是锁着的,任何时候有人按一个密码键就会产生一个事件,这个键值和前面的按键组合后与密码相比较,看是否正确,如果输入的密码顺序是对的,那么将门打开10秒,如果输入密码不完全,则等待下次按钮按下,如果输入密码顺序是错的,则重新开始等待按键按下。

首先了解一些基础

接下来看代码 注释都在其中

 1 %% gen_fsm 测试
 2 -module(code_lock).
 3 -behaviour(gen_fsm).
 4
 5 -export([start_link/1]).
 6 -export([button/1]).
 7
 8 -export([init/1, locked/2, open/2, stop/0]).
 9 -export([code_change/4, handle_event/3, handle_info/3, handle_sync_event/4, terminate/3]).
10
11 %% 如果进程注册成功,则新的gen_fsm进程调用code_lock:init(Code),
12 %% 返回{ok, StateName, StateData}。StateName是gen_fsm的初始状态,在这里返回的是locked,表示初始状态下门是锁着的,
13 %% 此处StateName(locked)也表示当调用gen_fsm:send_event/2时的回调函数
14 %% StateData是gen_fsm的内部状态,在这里Statedata是当前的按键顺序(初始时为空)和正确的锁代码,是个列表
15 -spec(start_link(Code::string()) -> {ok,pid()} | ignore | {error,term()}).
16 % start_link调用gen_fsm:start_link/4,启动一个新的gen_fsm进程并连接
17 start_link(Code) ->
18     % 第一个参数{local, code_lock}指定名字,在本地注册为code_lock
19     % 第二个参数code_lock是回调模块
20     % 第三个参数Code是传递给回调模块init函数的参数,就是密码锁的密码
21     % 第四个[]是状态机的选项
22     gen_fsm:start_link({local, code_lock}, code_lock, Code, []).
23
24 init(LockCode) ->
25     io:format("init: ~p~n", [LockCode]),
26     {ok, locked, {[], LockCode}}.
27
28 %% 使用gen_fsm:send_event/2来实现按建事件的通知
29 %% gen_fsm:send_event -> Module:StateName/2
30 %% Module为init()中的第二个参数code_lock回调模块,StateName为回调函数,即code_lock:locked
31 -spec(button(Digit::string()) -> ok).
32 button(Digit) ->
33     gen_fsm:send_event(code_lock, {button, Digit}).
34
35 locked({button, Digit}, {SoFar, Code}) ->
36     io:format("buttion: ~p, So far: ~p, Code: ~p~n", [Digit, SoFar, Code]),
37     % 将输入的值连接起来
38     InputDigits = lists:append(SoFar, Digit),
39     case InputDigits of
40         Code ->     % 密码输入正确
41             do_unlock(),    % 解锁时要执行的代码可以放在do_unlock()方法中
42             {next_state, open, {[], Code}, 10000};      % 解锁后状态为open,也表示超时10秒后调用open函数
43         Incomplete when length(Incomplete)<length(Code) ->  % 输入的密码长度小于真实密码的长度(即输入未完成)
44             {next_state, locked, {Incomplete, Code}, 5000}; % 超时5秒后调用locked(timeout,{SoFar, Code})方法
45         Wrong ->    % 密码输入错误
46             io:format("wrong passwd: ~p~n", [Wrong]),
47             {next_state, locked, {[], Code}}    % 输入错误则直接清空已经输入的密码
48     end;
49 locked(timeout, {_SoFar, Code}) ->
50     io:format("timout when waiting button inputting, clean the input, button again plz~n"),
51     {next_state, locked, {[], Code}}.   % 超时清空已经输入的密码
52
53 open(timeout, State) ->
54     do_lock(),  % 上锁时要执行的代码可以放在do_unlock()方法中
55     {next_state, locked, State}.    % 解锁超时后则将状态该为上锁状态
56
57 code_change(_OldVsn, StateName, Data, _Extra) ->
58     {ok, StateName, Data}.
59
60 terminate(normal, _StateName, _Data) ->
61     ok.
62
63 %% gen_fsm:send_all_state_event(CallModule, Event) -> CallModule:handle_event(Event, StateName, Data)
64 %% gen_fsm:send_all_state_event(code_lock, stop) -> code_lock:handle_event(stop, StateName, Date)
65 stop() ->
66     gen_fsm:send_all_state_event(code_lock, stop).
67
68 %% 有时候一个事件可以到达gen_fsm进程的任何状态,
69 %% 取代用gen_fsm:send_event/2发送消息和写一段每个状态函数处理事件的代码,
70 %% 这个消息我们可以用gen_fsm:send_all_state_event/2 发送,用Module:handle_event/3处理
71 handle_event(Event, StateName, Data) ->
72     io:format("handle_event... ~n"),
73     unexpected(Event, StateName),
74     {next_state, StateName, Data}.
75
76 %% gen_fsm:sync_send_all_state_event -> Module:handle_sync_event/4
77 handle_sync_event(Event, From, StateName, Data) ->
78     io:format("handle_sync_event, for process: ~p... ~n", [From]),
79     unexpected(Event, StateName),
80     {next_state, StateName, Data}.
81
82 handle_info(Info, StateName, Data) ->
83     io:format("handle_info...~n"),
84     unexpected(Info, StateName),
85     {next_state, StateName, Data}.
86
87
88 %% Unexpected allows to log unexpected messages
89 unexpected(Msg, State) ->
90     io:format("~p RECEIVED UNKNOWN EVENT: ~p, while FSM process in state: ~p~n",
91               [self(), Msg, State]).
92
93 %% actions
94 do_unlock() ->
95     io:format("passwd is right, open the DOOR.~n").
96
97 do_lock() ->
98     io:format("over, close the DOOR.~n"). 

测试结果:

本人查找的一些资料加上个人的理解,如果有错误,请务必指出来,十分感激,谢谢...

时间: 2024-10-27 13:15:01

Erlang OTP学习(1)gen_fsm的相关文章

Erlang OTP设计原则Gen_Fsm行为[转]

转自: http://www.cnblogs.com/yourihua/archive/2012/05/13/2497776.html 1. Fsm 称为 有限状态机,举个例子,游戏中的怪物称为NPC,NPC一般有几种状态,比如:静止,移动,死亡,被攻击,攻击英雄等等几个有限的状态,那么我们就可以有限状态机实现NPC的状态变更. 一个有限状态机可以用一个关系式来描述,State(静止状态S1) x Event(英雄进入视野范围事件E) -> Actions(开始移动动作A), State(移动状

Erlang OTP学习(1)gen_server

在<Programming Erlang>的OTP introduction章节中,作者通过循序渐进的方式,向我们展示了gen_server设计思路,现在做下总结: 在具体看gen_server之前,我们先看一个server通用框架:  在这个server里,你几乎看不到任何和具体功能相关的东西,它只提供了一个server所具备的基本框架,那它是如何运行的呢? 当我们调用start函数时,就启动了一个服务,如果服务器接收到一条消息,那么它将会把这条消息转交给Mod:handle_call或者M

Erlang OTP学习:supervisor [转]

转自: http://diaocow.iteye.com/blog/1762895 今天细致的看了下supervisor,现在做个总结: 其中,方块代表supervisor process,它的功能很简单,就负责看管它下面的“小弟”(child processes) 并且在必要的时候对某个child process执行restart或者terminate操作:而圆形就代表worker process,它才是真正负责干活的process:特别注意,supervisor process 监控的不一定

理解Erlang/OTP Supervisor

http://www.cnblogs.com/me-sa/archive/2012/01/10/erlang0030.html Supervisors are used to build an hierarchical process structure called a supervision tree, a nice way to structure a fault tolerant application.                                         

标准 Erlang/OTP 行为

参考资料 http://erlang.shiningray.cn/otp-design-principles/index.html 标准 Erlang/OTP 行为有: gen_server 用于实现 C/S 结构中的服务端. gen_fsm 用于实现有限状态机. gen_event 用于实现事件处理功能. supervisor 用于实现监督树中的督程.

启动erlang/OTP里面的Web服务器

erlang OTP是一个完整可靠的大型库,乃前人艰苦卓绝之成就:现在尝试一下里面的application inets的Web服务器httpd,写一段代码调用inets服务: 1 -module(inets_httpd). 2 -export([start/0]). 3 4 start() -> 5 inets:start(), 6 inets:start(httpd, [{bind_address, {192,168,178,130}}, {ipfamily, inet}, {port, 18

[Erlang 0127] Term sharing in Erlang/OTP 上篇

之前,在 [Erlang 0126] 我们读过的Erlang论文 提到过下面这篇论文: On Preserving Term Sharing in the Erlang Virtual Machine 地址: http://user.it.uu.se/~kostis/Papers/erlang12_sharing.pdf  摘要:In this paper we describe our experiences and argue through examples why ?attening t

Erlang/OTP 中文手册

http://erldoc.com/ Open Telecom Platform application array asn1rt base64 binary calendar code dbg dict erlang ets file filelib gb_trees gen_tcp inet io lists make maps math mnesia net_adm os proplists random re rpc string sys unicode Erlang并发编程 Erlan

理解Erlang/OTP - Application

http://www.cnblogs.com/me-sa/archive/2011/12/27/erlang0025.html 1>application:start(log4erl). 我们就从这一行命令开始说起吧,回车之后可以把log4erl应用程序启动起来.Erlang/OTP中的能完成特定功能集合的组件被称为application. ,application是Erlang代码和功能组织的形式之一([Erlang 0015]Erlang OTP设计原则).application的设计目的是