调用gen_server启动的方法
gen_server :start_link ( { local, ?MODULE } , ?MODULE , [ ] , [ ] ) .
参数分别是Name,Mod,Arg,Options
Options里可以设置timeout
gen.erl里的简单小函数取得timeout
timeout(Options) ->
case opt(timeout, Options) of
{ok, Time} ->
Time;
_ ->
infinity
end.
spawn_opts(Options) ->
case opt(spawn_opt, Options) of
{ok, Opts} ->
Opts;
_ ->
[]
end.
opt(Op, [{Op, Value}|_]) ->
{ok, Value};
opt(Op, [_|Options]) ->
opt(Op, Options);
opt(_, []) ->
false.
gen_server启动流程大体如下:
在我们的程序里启动一般调用如下:
gen_server :start_link ( { local, ?MODULE } , ?MODULE , [ ] , [ ] ) .
gen_server.erl 里
start_link(Name, Mod, Args, Options) ->
gen:start(?MODULE, link, Name, Mod, Args, Options).
gen.erl里基本是这样
do_spawn(GenMod, link, Mod, Args, Options) ->
Time = timeout(Options),
proc_lib:start_link(?MODULE, init_it,
[GenMod, self(), self(), Mod, Args, Options],
Time,...
proc_lib是一个关于进程的工具类,提供了同步启动进程的机制
start_link(M,F,A,Timeout,SpawnOpts) when is_atom(M), is_atom(F), is_list(A) ->
Pid = proc_lib:spawn_opt(M, F, A, ensure_link(SpawnOpts)),
sync_wait(Pid, Timeout).
sync_wait(Pid, Timeout) ->
receive
{ack, Pid, Return} ->
Return;
{'EXIT', Pid, Reason} ->
{error, Reason}
after Timeout ->
unlink(Pid),
exit(Pid, kill),
flush(Pid),
{error, timeout}
end.
spawn_opt系列大体就是erlang:spawn系里的一个,是异步的,先调用了本模块的init_p,存放些上下文信息到进程字典,最终会回调gen_server,一会再说
同步的关键在sync_wait这句,一看就懂了
上面的spawn经过fun的传来传去最终回到了gen_server.erl
init_it(Starter, self, Name, Mod, Args, Options) ->
init_it(Starter, self(), Name, Mod, Args, Options);
init_it(Starter, Parent, Name0, Mod, Args, Options) ->
Name = name(Name0),
Debug = debug_options(Name, Options),
case catch Mod:init(Args) of
{ok, State} ->
proc_lib:init_ack(Starter, {ok, self()}),
loop(Parent, Name, State, Mod, infinity, Debug);
{ok, State, Timeout} ->
proc_lib:init_ack(Starter, {ok, self()}),
loop(Parent, Name, State, Mod, Timeout, Debug);
{stop, Reason} ->
%% For consistency, we must make sure that the
%% registered name (if any) is unregistered before
%% the parent process is notified about the failure.
%% (Otherwise, the parent process could get
%% an 'already_started' error if it immediately
%% tried starting the process again.)
unregister_name(Name0),
proc_lib:init_ack(Starter, {error, Reason}),
exit(Reason);
ignore ->
unregister_name(Name0),
proc_lib:init_ack(Starter, ignore),
exit(normal);
{'EXIT', Reason} ->
unregister_name(Name0),
proc_lib:init_ack(Starter, {error, Reason}),
exit(Reason);
Else ->
Error = {bad_return_value, Else},
proc_lib:init_ack(Starter, {error, Error}),
exit(Error)
end.
看见这句了吧
catch Mod:init(Args)