https://www.cnblogs.com/hzy1987/p/5441807.html
http://www.cnblogs.com/me-sa/archive/2011/12/20/erlang0023.html
介绍:
gen_server是OTP的一个behavior, 在behavior基础上快速构建出可用且可靠的功能.
behavior是进程模式的规范化,把代码分成两部分,一部分是通用部分(behavior模块),一部分是定制部分(回调模块).对于gen_server就是要把client/server的模型进行一个抽象和封装,把behavior和回调模块需要完成的职责分离开.
启动流程:
- 调用启动函数, start/3, start/4, start_link/3, start_link/4, 选择其中一个, 这里以常见的start_link/4为例,实际上是调用了gen:start, 第二个参数表示与父节点建立链接,即新启动的进程死掉后,会不会通知启动他的进程(父进程).
- 进入gen:start/6, 首先判断使用Name名字的进程是否已经存在, 若注册了直接返回already_start, 若未注册则调用do_spawn/6,进入创建进程前的准备.
- 进入do_spawn/6, 检查启动参数是否有超时限制, 然后调用proc_lib:start_link, 真正创建一个进程.
- 进入创建进程的阶段, 此时函数调用位于子进程, 调用init_it/6, 首先判断Name是否已经注册,与where类似,需要根据名字是全局(global),本节点(local),转发(via)而定, 未注册则进入init_it2函数.
-
进入init_it2/7, 实际直接调用gen_server:init_it.
-
gen_server:init/7, 调用Mod:init/1, 调用逻辑模块的init函数,返回{ok,State}则创建成功,
此时给父进程发送{ack,self(),{ok,self()}消息, proc_lib:sync_wait接收到后, 返回{ok,ChildPid}到父进程, 父进程的gen_server:start_link函数结束.
然后进程在运行状态通过loop方法来实现状态循环,loop方法的职责就是receive-evaluate,接受到消息,处理,更新进程状态,并把进程状态作为尾递归的参数传递回去, 此时一个gen_server创建完毕.
ps: proc_lib:start_link函数, 里面会同步等待子进程返回{ack,Pid,Return}消息.
- gen_server:loop/6, receive显示接受消息,然后调用decode_msg对消息进行处理.
消息发送与接收:
发送:
gen_server提供的方式有两种:
- call: 同步调用, 调用gen:call, 消息格式为{’$gen_call’, {self(),MRef}, Request}, monitor用于监控目标进程是否存在,
同时返回MRef, 是一个唯一引用, 用于接收返回消息时做消息的模式匹配识别,对应对端的回调函数为
handle_call. 同步调用本质上是erlang:send发送消息, 然后调用receive接收指定消息(MRef}的返回. - cast: 异步调用, 调用gen:cast, 消息格式为{’$gen_cast, Request}.
接收:
gen_server:loop/6, 会不断receive接收消息, 然后调用decode_msg函数进行消息处理,这里就说说decode_msg.
对Msg进行模式匹配,
-
{EXIT,Parent,Reanson}则表示受到终止进程的消息,调用terminate进入扫尾工作,例如关闭已打开的资源,
文件,网络连接,打log,数据保存等. -
其余则进入handle_msg处理,目前debug参数为[].
handle_msg: -
消息为{’$gen_call’, From, Msg}则表示发送方调用了 gen_server:call, 接收方调用
Mod:handle_call处理. -
消息为{’$gen_cast’,Msg}则表示发送方调用了 gen_server:cast, 接收方调用Mod:handle_cast处理.
其他消息一般表示原生消息, 例如socket发来的消息, 发送方使用 ! 发来的消息, 与本进程建立连接的进程挂掉, -
发送{‘EXIT’,Pid,Why}等, 接收方调用Mod:handle_info处理.
关闭进程方式:
让handle_call, handle_cast, 或handle_info最后返回 {stop,normal,State}消息, 然后就调用terminate函数, 调用Mod:terminate,
所以需要写一条接收关闭进程消息的处理函数.
网友评论