`
hideto
  • 浏览: 2678857 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

OTP Design Principles: Gen_Fsm Behaviour

UP 
阅读更多
1,有限状态机
FSM,有限状态机,可以用以下形式来描述做一个关系集:
State(S) x Event(E) -> Actions(A), State(S')

意思是,如果我们位于状态S,然后事件E发送了,则我们应该执行动作A,并且将状态改为S'

2,例子
有一个代码锁的门,如果输入的代码顺序是对的,那么将门打开30秒
如果输入代码不完全,则等待下次按钮按下,如果输入代码顺序是错的,则重新开始等待按钮按下
-module(code_lock).
-behaviour(gen_fsm).

-export([start_link/1]).
-export([button/1]).
-export([init/1, locked/2, open/2]).

start_link(Code) ->
  gen_fsm:start_link({local, code_lock}, code_lock, Code, []).

button(Digit) ->
  gen_fsm:send_event(code_lock, {button, Digit}).

init(Code) ->
  {ok, locked, {[], Code}}.

locked({button, Digit}, {SoFar, Code}) ->
  case [Digit|SoFar] of
    Code ->
      do_unlock(),
      {next_state, open, {[], Code}, 3000};
      Incomplete when length(Incomplete) < length(Code) ->
        {next_state, locked, {Incomplete, Code}};
      _Wrong ->
        {next)state, locked, {[], Code}};
  end.

open(timeout, State) ->
  do_lock(),
  {next_state, locked, State}.


3,启动Gen_Fsm
上面的例子里,使用code_lock:start_link(Code)启动gen_fsm:
start_link(Code) ->
  gen_fsm:start_link({locak, code_lock}, code_lock, Code, []).

start_link调用gen_fsm:start_link/4,启动一个新的gen_fsm进程并连接。
1)第一个参数{local, code_lock}指定名字,在本地注册为code_lock
2)第二个参数code_lock执行callback模块
3)第三个参数Code是传递给callback方法init的参数,在这里init方法得到正确的代码锁的代码
4)第四个采纳数[]是options
如果进程注册成功,则新的gen_fsm进程调用callback方法code_lock:init(Code),返回{ok, StateName, StateData}
StateName是gen_fsm的初始状态,在这里返回的是locked,表示初始状态下门是锁着的
StateData是gen_fsm的内部状态,在这里state data是当前的按钮顺序(初始时为空)和正确的锁代码
init(Code) ->
  {ok, locked, {[], Code}}.

注意gen_fsm:start_link是同步的,直到gen_fsm进程初始化并准备好开始接受请求时才会返回
gen_fsm:start_link表示有supervisor,gen_fsm:start则是启动单独的gen_fsm进程

4,事件通知
使用gen_fsm:send_event/2来实现按钮事件的通知:
button(Digit) ->
  gen_fsm:send_event(code_lock, {button, Digit}).

code_lock是gen_fsm进程的名字,{button, Digit}是真正的事件
事件会当成消息发送给gen_fsm进程,事件接收以后,gen_fsm调用StateName(Event, StateData)并返回{next_state, StateName1, StateData1}
StateName是当前状态的名字,StateName1是下一个即将变成的状态的名字,StateData1是gen_fsm的新的state data值:
locked({button, Digit}, {SoFar, Code}) ->
  case [Digit|SoFar] of
    Code ->
      do_unlock(),
      {next_state, open, {[], Code}, 3000};
    Incomplete when length(Incomplete) < length(Code) ->
      {next_state, locked, {Incomplete, Code}};
    _Wrong ->
      {next_state, locked, {[], Code}};
  end.

open(timeout, State) ->
  do_lock(),
  {next_state, locked, State}.

如果门是锁着的,这时按下一个按钮,则比较目前按钮的顺序和正确的代码顺序,由比较结果来决定是unlock门还是继续保持locked

5,超时
当输入正确的按钮顺序后,门unlock然后返回如下的tuple:
{next_state, open, {[], Code}, 30000};

30000表示超时时间为30000毫秒,在30000毫秒之后,发生超时,超时后调用StateName(timeout, StateData)
在这里,门打开30秒之后再次锁上:
open(timeout, State) ->
  do_lock(),
  {next_state, locked, State}.


6,所有的状态事件
有时候一个事件可以到达gen_fsm进程的任何状态,这时消息可以使用gen_fsm:send_all_state_event/2来发送消息,然后用Module:handle_event/3来处理
-module(code_lock).
...
-export([stop/0]).
...

stop() ->
  gen_fsm:send_all_state_event(code_lock, stop).
...

handle_event(stop, _StateName, StateData) ->
  {stop, normal, StateData}.


7,停止
7.1 在Supervision Tree里
如果gen_fsm在supervision tree里,则不需要stop方法,gen_fsm会自动被supervisor停止
如果需要在结束前清理数据,那么shutdown strategy必须为一个timeout,并且必须在gen_fsm的init方法里设置捕获exit信号,然后
gen_fsm进程会调用callback方法terminate(shutdown, StateName, StateData)
init(Args) ->
  ...,
  process_flag(trap_exit, true),
  ...,
  {ok, Statename, StateData}.
...
terminate(shutdown, StateName, StateData} ->
  ..code for cleaning up here..
  ok.

7.2 单独的Gen_Fsms进程
如果gen_fsm进程没有supervisor,则需要一个stop方法:
...
-export([stop/0]).
...

stop() ->
  gen_fsm:send_all_state_event(code_lock, stop).
...

handle_event(stop, _StateName, StateData) ->
  {stop, normal, StateData}.
...

terminate(normal, _StateName, _StateData) ->
  ok.

callback方法处理stop事件并返回{stop, normal, StateData1},normal表示正常停止,StateData1为gen_fsm的新的data data值
这将导致gen_fsm调用terminate(normal, StateName, StateData1)然后优雅的停止

8,处理其他消息
其他消息的处理callback方法为handl_info(Info, StateName, StateData),例如连接到其他非supervisor进程并捕获exit信号时处理exit消息:
handle_info({'EXIT', Pid, Reason}, StateName, StateData) ->
  ..code to handle exits here..
  {next_state, StateName1, StateData1}.


补充:gen_fsm exports and callbacks
gen_fsm module                          Callback module
gen_fsm:start_link -------------------> Module:init/1
gen_fsm:start
gen_fsm:send_event -------------------> Module:StateName/2
gen_fsm:send_all_state_event ---------> Module:handle_event/3
gen_fsm:sync_send_event --------------> Module:StateName/3
gen_fsm:sync_send_all_state_event ----> Module:handle_sync_event/4
gen_fsm:reply
gen_fsm:send_event_after
gen_fsm:start_timer
gen_fsm:cancel_timer
gen_fsm:enter_loop
                                        Module:handle_info/3
                                        Module:terminate/3
                                        Module:code_change/4
分享到:
评论

相关推荐

    erlang OTP Design Principles之Gen中文

    Erlang OTP设计原则中的Gen_Fsm行为是一个关键的概念,用于构建健壮、可扩展的并发应用程序。Gen_Fsm,即通用有限状态机,是一种行为模式,它提供了一种结构化的方法来处理具有多种状态和事件的系统。本文将深入探讨...

    Erlang安装包,版本:otp_win64_24.1.7.exe

    otp_win64_24.1.7.exe

    erl:otp_src_24.0.5.tar.gz

    标题中的"erl:otp_src_24.0.5.tar.gz"指的是Erlang的源码包,其中"otp_src_24.0.5"是Erlang/OTP (Open Telecom Platform) 的24.0.5版本的源代码。Erlang是一种面向并发的、函数式的编程语言,常用于构建高可用性和...

    OTP Design Principles

    - **通知事件**:通过`gen_fsm:send_event/2`函数发送事件。 - **超时**:可以通过设置定时器来触发状态转换。 - **所有状态事件**:某些事件可以在任何状态下被处理。 - **停止**:使用`gen_fsm:stop/1`函数停止。 ...

    分布式应用Erlang:Erlang_OTP_19_win64

    Erlang OTP 19_win64是一款专为Windows 64位系统设计的Erlang软件开发工具包,它包含Erlang编程语言和OTP(Open Telecom Platform)框架。Erlang是一种强大的、动态类型的函数式编程语言,特别适合构建高可用性、...

    gen_state_machine:OTP 19(及更高版本)中gen_statem的惯用Elixir包装器

    OTP 20(及更高版本)中gen_statem的惯用Elixir包装器。 完整文档可。 您可以在在Hex上找到该软件包。 gen_statem和此包装器之间的一个重要区别是,您在此包装器use GenStateMachine回调模式声明为use ...

    otp_src_22.0_h.tar.gz

    OTP提供了几个设计良好的应用框架,如gen_server、gen_event、gen_fsm等,它们是基于行为模式的模块,简化了并发编程和状态管理。 5. **分布式功能** OTP支持跨节点的分布式计算,使得在多台机器上构建分布式系统...

    Erlang otp_win64_21.1.exe otp_win32_21.1.exe

    它包含了一系列预定义的模块、行为(如GenServer、GenEvent和Gen_fsm)以及设计原则,这些都旨在帮助开发者创建可靠和可扩展的应用程序。例如,Erlang的进程模型允许程序中的组件独立运行,通过消息传递进行通信,这...

    pin_code_fields:Flutter软件包,将帮助您生成具有精美设计和动画的PIN码字段。 可以用于OTP或Pin码输入:nerd_face::nerd_face:

    可用于OTP或Pin码输入 :nerd_face: :nerd_face: 特征 :green_heart: 自动将下一个字段集中在键入上,将上一个字段集中在删除上 游标支持 :high_voltage: 可以设置为任意长度。 (建议3-6个字段) 文本字段的3种...

    otp_win64_26.1.2.jpg

    otp_win64_26.1.2.jpg

    otp_src_21.2_linux.rar

    OTP(Open Telecommunications Platform)是Erlang编程语言的核心组件之一,主要为构建高可用、分布式和实时系统提供强大的工具。OTP源代码包通常包含了Erlang运行时系统、库和开发工具,使得开发者能够在各种操作...

    otp_verify_java.rar_OTP_OTPVerify_TOTP_otp算法_一次性 口令

    OTP(One-Time Password)是一种基于时间、事件或挑战/应答机制的一次性密码技术,用于提高用户身份验证的安全性。OTP确保每个密码只能使用一次,从而降低了密码被重放攻击的风险。在Java环境中,我们可以使用不同的...

    RabbitMQ系统客户端连接到RabbitMQ服务端消息通信过程1

    - `amqp_gen_connection`使用`gen_tcp:connect`与服务器建立TCP连接。服务器端响应并启动`rabbit_client_sup`监督树,包括`rabbit_connection_sup`,进一步创建`rabbit_connection_helper_sup`和`rabbit_reader`...

    OTP.zip_OTP_OTP .nd pudn_java otp_otp java_verify

    在本项目中,“OTP.zip”是一个压缩包,其中包含了实现OTP生成和验证功能的Java代码。 OTP通常基于时间同步(TOTP)或基于挑战-响应的哈希算法(HMAC)两种方式。在这个"OTP"项目中,可能使用了TOTP,因为它是目前...

    gen_server tasting 之超简单名称服务(续)

    在IT行业中,`gen_server`是Erlang OTP(开放电信平台)框架中的一个核心组件,它提供了一种模式化的方式来实现服务器进程。本篇博客“gen_server tasting 之超简单名称服务(续)”主要探讨了如何使用gen_server来...

    基于Erlang的gen_tcp聊天室代码,功能完整

    - 处理连接请求,为每个新连接创建一个新的进程(通常是一个gen_server或gen_fsm行为)。 - 注册和登录逻辑,处理用户认证请求。 - 监听和转发消息,确保消息在正确用户间传递。 - 错误处理和异常恢复,确保系统的...

    erlang_otp_win64_25.0

    Erlang OTP (Open Telephony Platform) 是一种高级并发编程语言和框架,主要由瑞典电信设备制造商Ericsson开发,用于构建高度可靠、可扩展和实时的分布式系统。Erlang OTP 25.0是该平台的一个版本,特别针对Windows ...

    otp.rar_OTP_otp显示程序_otp烧录显示屏_显示屏OTP

    OTP(One-Time Programmable)是一种只可编程一次的非易失性存储器技术,常用于存储固定配置数据或密钥。在显示屏领域,OTP被用来烧录特定的参数,如对比度、亮度等,以确保显示器在出厂时具有最佳的显示效果。 在...

    使用OTP原理构建一个非阻塞的TCP服务器

    OTP为开发健壮、容错的应用提供了强大的框架,它包含了一系列行为模式,如gen_server和gen_fsm,这些模式可以帮助我们构建高效、可扩展的服务。 首先,我们需要理解什么是非阻塞TCP服务器。在Erlang中,"非阻塞"指...

    otp_win64_23.1.exe|otp_win64_23.1.zip

    4. 安装和配置Erlang OTP:学会如何在不同的操作系统上安装和配置Erlang环境,包括环境变量设置。 5. 安装RabbitMQ:熟悉RabbitMQ的安装过程,包括通过Erlang环境安装RabbitMQ服务器、管理插件和其他依赖项。 6. ...

Global site tag (gtag.js) - Google Analytics