2012-08-23 61 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

相关问题