http://bachmozart.iteye.com/blog/470506
调用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)