gen_server是erlang otp封装的beheivor模块。
一、gen_server start初始化过程
1、gen_server_start*启动进程,初始化数据,进入loop。gen_server_start*调用gen:start(通过proc_lib:start*创建进程)创建进程。
2、gen执行gen:init_it方法,gen:init_it通过调用gen_server:init_it,gen_server:init_it调用Mod:init实现模块回调,回调成功,执行proc_lib:init_ack,然后进入gen_server:loop等待消息。
3、gen_server:loop收到消息后调用回调模块mod:handle_call mod:handle_cast mod:handle_info处理消息,处理完成后执行gen_server:loop。
4、如果异常,调用gen_server:terminate处理异常,该函数会掉用回调模块mod:terminate执行异常处理,并退出进程exit
二、gen_server:call
1、gen_server:call通过调用gen:call实现call的。gen:call处理进程信息,然后调用gen:do_call来实现call动作
2、do_call 先调用erlang:monitor监控进程,然后调用erlang:send发送消息,receive reply或者DOWN消息,解除监控erlang:demonitor。如果进程无法监控(crash),监控节点monitor_node(Node,false) ,直接发消息给进程,receive reply或者nodedown,结束节点监控monitor_node(Node,false)。
3、当监控进程时会进行节点连接,所有在发消息时可以认为是已连接状态,设置参数noconnect。
do_call(
Process
,
Label
,
Request
,
Timeout
)
->
%% We trust the arguments to be correct, i.e
%% Process is either a local or remote pid,
%% or a {Name, Node} tuple (of atoms) and in this
%% case this node (node()) _is_ distributed and Node =/= node().
Node
=
case
Process
of
{
_S
,
N
}
when
is_atom(
N
)
->
N
;
_
when
is_pid(
Process
)
->
node(
Process
)
end
,
try
erlang:monitor(process,
Process
)
of
Mref
->
%% If the monitor/2 call failed to set up a connection to a
%% remote node, we don't want the '!' operator to attempt
%% to set up the connection again. (If the monitor/2 call
%% failed due to an expired timeout, '!' too would probably
%% have to wait for the timeout to expire.) Therefore,
%% use erlang:send/3 with the 'noconnect' option so that it
%% will fail immediately if there is no connection to the
%% remote node.
catch
erlang:send(