启动一个Gen_Fsm

在上一节的例子中,该gen_fsm是通过调用 code_lock:start_link(Code) 来启动的:

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

start_link 调用函数 gen_fsm:start_link/4。该函数产生并连接到一个新的gen_fsm进程.

  • 第一个参数 {local,code_lock} 指明了名字。在这里,gen_fsm会在本地注册为 code_lock 。如果名字被省略了,那么将不会注册gen_fsm。这样就必须使用它的pid。名字也可以这样写 {global,Name}, 这样,gen_fsm就是使用 global_register_name/2 来注册了。
  • 第二个参数 code_lock 是回调模块的名字,也就是回调函数所位于的模块。在这个例子里面,接口函数(start_link 和 button)是位于和回调函数(init, locked 和 open)相同的模块中。这一般是较好的编程实践,让一个进程对应的代码包含在一个模块里面。
  • 第三个参数 Code 是一个值,将被原封不动传递给回调函数 init 。这里, init 得到锁的正确代码做为内部数据。
  • 第四个参数 [] 是一个选项的列表。参见 gen_fsm(3) 来找到可用的选项。如果名称注册成功,新的gen_fsm进程会调用回调函数 code_lock:init(Code)。这个函数要返回 {ok,StateName,StateData},其中 StateName 是gen_fsm初始状态的名字。在这个例子里面是 locked,假设门一开始是锁着的。 StateData 是gen_fsm的内部状态。(对于gen_fsm来说,内部状态一般是指“状态数据”(state data),以区别于状态机的状态)。在这个例子里面,状态数据(state data)是到目前为止的按钮的顺序(开始的时候为空)和锁的正确密码顺序。
  1. init( Code ) ->
  2. {ok, locked, {[], Code}}.

注意gen_fsm:start_link是同步的。它只有到gen_fsm已经完成初始化并且可以接收通知的时候才返回。

如果gen_fsm是一个监毒树的一部分的话——即由督程启动的——必须使用 gen_fsm:start_link 。有另外一个函数 gen_fsm:start 来启动一个独立的gen_fsm——即,gen_fsm不属于监督树的一部分。