gen_server源码杂记

http://bachmozart.iteye.com/blog/470506

调用gen_server启动的方法 

gen_server :start_link ( { local, ?MODULE } , ?MODULE , [ ] , [ ] ) . 
参数分别是Name,Mod,Arg,Options 

Options里可以设置timeout 

gen.erl里的简单小函数取得timeout 

Java代码   收藏代码
  1. timeout(Options) ->  
  2.     case opt(timeout, Options) of  
  3.     {ok, Time} ->  
  4.         Time;  
  5.     _ ->  
  6.         infinity  
  7.     end.  
  8.   
  9. spawn_opts(Options) ->  
  10.     case opt(spawn_opt, Options) of  
  11.     {ok, Opts} ->  
  12.         Opts;  
  13.     _ ->  
  14.         []  
  15.     end.  
  16.   
  17. opt(Op, [{Op, Value}|_]) ->  
  18.     {ok, Value};  
  19. opt(Op, [_|Options]) ->  
  20.     opt(Op, Options);  
  21. opt(_, []) ->  
  22.     false.  


gen_server启动流程大体如下: 
在我们的程序里启动一般调用如下: 
Java代码   收藏代码
  1. gen_server :start_link ( { local, ?MODULE } , ?MODULE , [ ] , [ ] ) .  


gen_server.erl 里 
Java代码   收藏代码
  1. start_link(Name, Mod, Args, Options) ->  
  2.     gen:start(?MODULE, link, Name, Mod, Args, Options).  


gen.erl里基本是这样 
Java代码   收藏代码
  1. do_spawn(GenMod, link, Mod, Args, Options) ->  
  2.     Time = timeout(Options),  
  3.     proc_lib:start_link(?MODULE, init_it,  
  4.             [GenMod, self(), self(), Mod, Args, Options],   
  5.             Time,...  


proc_lib是一个关于进程的工具类,提供了同步启动进程的机制 

Java代码   收藏代码
  1. start_link(M,F,A,Timeout,SpawnOpts) when is_atom(M), is_atom(F), is_list(A) ->  
  2.     Pid = proc_lib:spawn_opt(M, F, A, ensure_link(SpawnOpts)),  
  3.     sync_wait(Pid, Timeout).  
  4.   
  5. sync_wait(Pid, Timeout) ->  
  6.     receive  
  7.     {ack, Pid, Return} ->  
  8.         Return;  
  9.     {'EXIT', Pid, Reason} ->  
  10.         {error, Reason}  
  11.     after Timeout ->  
  12.         unlink(Pid),  
  13.         exit(Pid, kill),  
  14.         flush(Pid),  
  15.         {error, timeout}  
  16.     end.  


spawn_opt系列大体就是erlang:spawn系里的一个,是异步的,先调用了本模块的init_p,存放些上下文信息到进程字典,最终会回调gen_server,一会再说 

同步的关键在sync_wait这句,一看就懂了 

上面的spawn经过fun的传来传去最终回到了gen_server.erl 

Java代码   收藏代码
  1. init_it(Starter, self, Name, Mod, Args, Options) ->  
  2.     init_it(Starter, self(), Name, Mod, Args, Options);  
  3. init_it(Starter, Parent, Name0, Mod, Args, Options) ->  
  4.     Name = name(Name0),  
  5.     Debug = debug_options(Name, Options),  
  6.     case catch Mod:init(Args) of  
  7.     {ok, State} ->  
  8.         proc_lib:init_ack(Starter, {ok, self()}),         
  9.         loop(Parent, Name, State, Mod, infinity, Debug);  
  10.     {ok, State, Timeout} ->  
  11.         proc_lib:init_ack(Starter, {ok, self()}),         
  12.         loop(Parent, Name, State, Mod, Timeout, Debug);  
  13.     {stop, Reason} ->  
  14.         %% For consistency, we must make sure that the  
  15.         %% registered name (if any) is unregistered before  
  16.         %% the parent process is notified about the failure.  
  17.         %% (Otherwise, the parent process could get  
  18.         %% an 'already_started' error if it immediately  
  19.         %% tried starting the process again.)  
  20.         unregister_name(Name0),  
  21.         proc_lib:init_ack(Starter, {error, Reason}),  
  22.         exit(Reason);  
  23.     ignore ->  
  24.         unregister_name(Name0),  
  25.         proc_lib:init_ack(Starter, ignore),  
  26.         exit(normal);  
  27.     {'EXIT', Reason} ->  
  28.         unregister_name(Name0),  
  29.         proc_lib:init_ack(Starter, {error, Reason}),  
  30.         exit(Reason);  
  31.     Else ->  
  32.         Error = {bad_return_value, Else},  
  33.         proc_lib:init_ack(Starter, {error, Error}),  
  34.         exit(Error)  
  35.     end.  


看见这句了吧 
catch Mod:init(Args) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值