2012-08-23 59 views
9

我很新的OTP,我試圖創建簡單的例子就明白了上司的行爲:爲什麼我的主管會終止?

下面是簡單的增量服務器

-module(inc_serv). 
-behaviour(gen_server). 
-export([ start/0, inc/1, stop/0 ]). 
-export([ init/1, handle_call/3, terminate/2 ]). 

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

stop() -> 
     gen_server:call(?MODULE, stop). 

inc(Num) -> 
     gen_server:call(?MODULE, { num, Num }). 

init(no_args) -> 
     io:format("~p~n", [ "Increment server started :)" ]), 
     { ok, no_state }. 

handle_call({ num, Num }, _From, no_state) -> 
     { reply, Num + 1, no_state }; 
handle_call(stop, _From, no_state) -> 
     { stop, normal, ok, no_state }. 

terminate(Reason, no_state) -> 
     io:format("~p~n", [ "Increment server stopped" ]). 

而且我想使其通過這種監督模塊:

-module(supervisor_inc). 
-behaviour(supervisor). 

-export([ start/0 ]). 
-export([ init/1 ]). 

start() -> 
     supervisor:start_link({ local, ?MODULE }, ?MODULE, no_args). 

init(no_args) -> 
     process_flag(trap_exit, true), 
     Supervisor_Spec = { one_for_one, 1, 1 }, 
     IncServ_Spec = { 
       inc_serv, 
       { inc_serv, start, [] }, 
       permanent, 2000, worker, [ inc_serv ] }, 
     { ok, { Supervisor_Spec, [ IncServ_Spec ] } }. 

在那之後,我在二郎殼下面的步驟進行:

1> 
1> c(inc_serv). 
{ok,inc_serv} 
2> 
2> c(supervisor_inc). 
{ok,supervisor_inc} 
3> 
3> supervisor_inc:start(). 
"Increment server started :)" 
{ok,<0.43.0>} 
4> 
4> inc_serv:inc(7). 
8 
5> inc_serv:inc(8). 
9 

這個我旁邊已經試過後(如我所料,我有錯誤):

6> inc_serv:inc(bad_arg). 
"Increment server stopped" 
"Increment server started :)" 

=ERROR REPORT==== 23-Aug-2012::19:32:06 === 
** Generic server inc_serv terminating 
** Last message in was {num,bad_arg} 
** When Server state == no_state 
** Reason for termination == 
** {badarith,[{inc_serv,handle_call,3,[{file,"inc_serv.erl"},{line,22}]}, 
       {gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,588}]}, 
       {proc_lib,init_p_do_apply,3, 
         [{file,"proc_lib.erl"},{line,227}]}]} 

=ERROR REPORT==== 23-Aug-2012::19:32:06 === 
** Generic server supervisor_inc terminating 
** Last message in was {'EXIT',<0.31.0>, 
          {{{badarith, 
           [{inc_serv,handle_call,3, 
             [{file,"inc_serv.erl"},{line,22}]}, 
            {gen_server,handle_msg,5, 
             [{file,"gen_server.erl"},{line,588}]}, 
            {proc_lib,init_p_do_apply,3, 
             [{file,"proc_lib.erl"},{line,227}]}]}, 
          {gen_server,call,[inc_serv,{num,bad_arg}]}}, 
          [{gen_server,call,2, 
           [{file,"gen_server.erl"},{line,180}]}, 
          {erl_eval,do_apply,6, 
           [{file,"erl_eval.erl"},{line,576}]}, 
          {shell,exprs,7,[{file,"shell.erl"},{line,668}]}, 
          {shell,eval_exprs,7, 
           [{file,"shell.erl"},{line,623}]}, 
          {shell,eval_loop,3, 
           [{file,"shell.erl"},{line,608}]}]}} 
** When Server state == {state, 
          {local,supervisor_inc}, 
          one_for_one, 
          [{child,<0.48.0>,inc_serv, 
           {inc_serv,start,[]}, 
           permanent,2000,worker, 
           [inc_serv]}], 
          undefined,1,1, 
          [{1345,739526,107495}], 
          supervisor_inc,no_args} 
** Reason for termination == 
** {{{badarith,[{inc_serv,handle_call,3,[{file,"inc_serv.erl"},{line,22}]}, 
       {gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,588}]}, 
       {proc_lib,init_p_do_apply,3, 
          [{file,"proc_lib.erl"},{line,227}]}]}, 
    {gen_server,call,[inc_serv,{num,bad_arg}]}}, 
    [{gen_server,call,2,[{file,"gen_server.erl"},{line,180}]}, 
    {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,576}]}, 
    {shell,exprs,7,[{file,"shell.erl"},{line,668}]}, 
    {shell,eval_exprs,7,[{file,"shell.erl"},{line,623}]}, 
    {shell,eval_loop,3,[{file,"shell.erl"},{line,608}]}]} 
** exception exit: {{badarith,[{inc_serv,handle_call,3, 
             [{file,"inc_serv.erl"},{line,22}]}, 
           {gen_server,handle_msg,5, 
              [{file,"gen_server.erl"},{line,588}]}, 
           {proc_lib,init_p_do_apply,3, 
             [{file,"proc_lib.erl"},{line,227}]}]}, 
        {gen_server,call,[inc_serv,{num,bad_arg}]}} 
    in function gen_server:call/2 (gen_server.erl, line 180) 

此我希望以後 - 我的上司重啓inc_serv。但它沒有:

7> inc_serv:inc(8).  
** exception exit: {noproc,{gen_server,call,[inc_serv,{num,8}]}} 
    in function gen_server:call/2 (gen_server.erl, line 180) 

你能幫我瞭解發生了什麼嗎?我應該如何改寫我的上司,使其能夠重新啓動inc_serv

感謝

回答

22

這其實是一種競爭狀態。如你所知,Erlang shell本身是一個普通的Erlang進程。當您從shell啓動主管時,主管鏈接到shell(因爲您使用的是supervisor:start_link/3)。

當您調用gen_server進程時,該進程崩潰(並且由主管正確重啓,正如後面的"Increment server started :)"輸出所示)。

然而,在同一時間,你的電話gen_server:call/2將導致死機一樣(一個gen_server在通話過程中撞擊會發出通過gen_server:call/2功能相同的崩潰)。然後,這會導致與您的主管鏈接的shell進程崩潰,而進程則以相同的原因崩潰(badarith)。

基本上,你的主管在你忠實地重新啓動你的gen_server之後,會被你的shell進程背靠。像這樣:

 +---------(6)exit----------+ +---------(5)restart---------+ 
     |       | |       | 
     |       v |       v 
    Shell ---(1)start_link---> supervisor ---(2)start_link---> gen_server 
    |^      ^ |      ^| ^
    | |       | |       | | | 
    | |       | +---------(7)exit---------+ | | 
    | |       |         | | 
    | +-------------------------+--------------(4)exit------------+ | 
    |                 | 
    +---------------------------(3)call--------------------------------+ 

您可以通過調用你的shell catch inc_serv:inc(bad_arg).避免這種情況:

90> inc_serv:inc(7).   
8 
91> catch inc_serv:inc(bad_arg). 
"Increment server stopped" 

=ERROR REPORT==== 23-Aug-2012::22:10:02 === 
** Generic server inc_serv terminating 
** Last message in was {num,bad_arg} 
** When Server state == no_state 
** Reason for termination == 
** {badarith,[{inc_serv,handle_call,3,[{file,"inc_serv.erl"},{line,20}]}, 
       {gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,588}]}, 
       {proc_lib,init_p_do_apply,3, 
         [{file,"proc_lib.erl"},{line,227}]}]} 
"Increment server started :)" 
{'EXIT',{{badarith,[{inc_serv,handle_call,3, 
           [{file,"inc_serv.erl"},{line,20}]}, 
        {gen_server,handle_msg,5, 
           [{file,"gen_server.erl"},{line,588}]}, 
        {proc_lib,init_p_do_apply,3, 
           [{file,"proc_lib.erl"},{line,227}]}]}, 
        {gen_server,call,[inc_serv,{num,bad_arg}]}}} 
92> inc_serv:inc(7).    
8 
+0

感謝偉大的答案! – stemm

相關問題