Archive

Posts Tagged ‘gen’

gen系列init使用注意事项

April 8th, 2010 2 comments

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: gen系列init使用注意事项

gen*都需要callback模块提供一个init模块, 在这个模块里面做相应的初始化操作.

我们以gen_server为例子. 当我们调用gen_server:start_link的时候,  底层会委托proc_lib来启动新的进程同时调用我们的init函数进行初始化.  同时gen系列会同步等待新进程初始化完毕, 才接着往下执行.

我们看下文档:

gen_server:start_link(ServerName, Module, Args, Options) -> Result
The gen_server process calls Module:init/1 to initialize. To ensure a synchronized start-up procedure, start_link/3,4 does not return until Module:init/1 has returned.

我们会经常误解这个行为, 以为start是马上返回的, otp团队之前也修正httpc的一个这类问题的bug.

所以我们在init的时候, 尽可能的做些简单的工作. 如果需要做费时的操作, 那么可以先让一条消息, 放到消息队列去, 让init马上返回. 这时候兵分二路, 调用进程可以继续往下执行, 费时操作也在稍后被调用.

而且gen*系列一旦启动起来, 如果该进程不幸发生意外崩溃,  proc_lib会负责记录当时的现场和原因,  非常有助于诊断.

我们演示下这个问题:

root@ubuntu:~# cat tg.erl


-module(tg).

-behaviour(gen_server).

%% API
-export([start/0]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).

-record(state, {}).
-define(SERVER, ?MODULE).

start() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

init([]) ->

io:format("init pid ~p~n", [self()]),

%% sleep
receive
after 3000 ->
cont
end,

erlang:send_after(0, self(), crash_me),

{ok, #state{}}.

handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.

handle_cast(_Msg, State) ->
{noreply, State}.

handle_info(crash_me, State) ->
% do some hard work

% crash me
exit(crash_me),
{noreply, State};

handle_info(_Info, State) ->
{noreply, State}.

terminate(_Reason, _State) ->
ok.

code_change(_OldVsn, State, _Extra) ->
{ok, State}.

root@ubuntu:~# erl
Erlang R13B04 (erts-5.7.5) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.5  (abort with ^G)
1> self().
<0.36.0>
2> timer:tc(tg, start, []).
init pid <0.34.0>
{3003583,{ok,<0.34.0>}}
2>
=ERROR REPORT==== 8-Apr-2010::16:20:09 ===
** Generic server tg terminating
** Last message in was crash_me
** When Server state == {state}
** Reason for termination ==
** crash_me
** exception error: crash_me
2>

1. 我们个tg:start启动了3003毫秒, 证明这是同步调用.

2. init是在新进程里面执行的
3. 我们的费时间操作用erlang:send_after发起
4. 一旦发生crash我们有记录在案.

收工!

Post Footer automatically generated by wp-posturl plugin for wordpress.

Categories: Erlang探索 Tags: ,