2017-05-24 9 views
0

要求を受け取ったときに一時的な処理を開始するサーバーを1つ設計しようとしました。しかし、一時的なプロセスを終了または終了しようとしたとき、私はnoprocエラーを受け取りました。誰も私にこの問題を解決する方法を教えてもらえますか?子プロセスを終了しようとするとErlang noprocエラーが発生する

私は、次のファイルだ:

temp.erl(メイン監督)

-module(temp). 
-behaviour(supervisor). 
-export([start_link/0, init/1]). 
-export([list_children/0]). 

start_link() -> 
    supervisor:start_link({local, ?MODULE}, ?MODULE, []). 

list_children() -> 
    supervisor:which_children(?MODULE). 

init([]) -> 
    process_flag(trap_exit, true), 
    io:format("****Main supervisor****~n"), 
    {ok, {{one_for_one, 5, 10}, 
      [{temp_srv, {temp_srv, start_link, []}, 
      permanent, infinity, worker, [temp_srv]}, 
      {temp_sup, {temp_sup, start_link, []}, 
      permanent, infinity, supervisor, [temp_sup]}]}}. 

temp_srv.erl(サーバー)

-module(temp_srv). 
-behaviour(gen_server). 
-export([init/1, handle_cast/2, handle_info/2, handle_call/3, terminate/2, code_change/3]). 
-export([start_link/0, echo_call/1]). 

-record(state, {}). 

-define(SERVER, ?MODULE). 

echo_call(Data) -> 
    gen_server:call(?SERVER, {echo, Data}). 

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

init([]) -> 
    process_flag(trap_exit, true), 
    {ok, #state{}}. 

handle_call({echo, Data}, _From, State) -> 
    Result = temp_sup:assign_task({echo, Data}), 
    {reply, Result, State}; 
handle_call(_Request, _From, State) -> 
    {noreply, State}. 

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

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

terminate(_Reason, _State) -> 
    ok. 

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

temp_sup.erl(監督者の一時的なプロセスを開始するために)

-module(temp_sup). 
-behaviour(supervisor). 
-export([start_link/0, init/1]). 
-export([start_temp_worker/0, list_children/0, assign_task/1, select_available_children/1, select_finished_children/1]). 

start_link() -> 
    supervisor:start_link({local, ?MODULE}, ?MODULE, []). 

list_children() -> 
     supervisor:which_children(?MODULE). 

init([]) -> 
    io:format("****Temp supervisor*****~n"), 
    spawn_link(fun start_pool/0), 
    {ok, {{simple_one_for_one, 0, 1}, [{temp_worker, {temp_worker, start_link, []}, temporary, 1000, worker, [temp_worker]}]}}. 

start_pool() -> 
     [start_temp_worker() || _ <- lists:seq(1, 3)]. 

start_temp_worker() -> 
     supervisor:start_child(?MODULE, []). 

assign_task(Data) -> 
     case list_children() of 
       [] -> 
         {ok, Pid} = start_temp_worker(), 
         gen_server:call(Pid, Data); 
       ChildL when is_list(ChildL) -> 
      case select_finished_children(ChildL) of 
       no_pid_to_kill -> ok; 
       {ok, KPid} -> gen_server:call(KPid, stop) 
      end, 
      {ok, Pid} = select_available_children(ChildL), 
      start_temp_worker(), 
      io:format("Assign task to ~p~n", [Pid]), 
      gen_server:call(Pid, Data) 
     end. 

select_available_children([ChildH | ChildT]) -> 
    {undefined, Pid, worker, [temp_worker]} = ChildH, 
    case gen_server:call(Pid, check_status) of 
     active -> 
      io:format("Find available children ~p~n", [Pid]), 
      {ok, Pid}; 
     running -> select_available_children(ChildT); 
     done -> select_available_children(ChildT) 
    end. 

select_finished_children([ChildH | ChildT]) -> 
    {undefined, KPid, worker, [temp_worker]} = ChildH, 
    case gen_server:call(KPid, check_status) of 
     done -> 
      io:format("Find process ~p to kill~n", [KPid]), 
      {ok, KPid}; 
     _ -> select_finished_children(ChildT) 
    end; 
select_finished_children([]) -> no_pid_to_kill. 

temp_worker.erl(一時的なプロセス)

-module(temp_worker). 
-behaviour(gen_server). 
-export([start_link/0, init/1]). 
-export([handle_info/2, handle_call/3, handle_cast/2, code_change/3, terminate/2]). 
-record(state, {status}). 

start_link() -> 
    gen_server:start_link(?MODULE, [], []). 

init([]) -> 
    process_flag(trap_exit, true), 
    io:format("Start temporary worker process ~p~n", [self()]), 
    {ok, #state{status = active}}. 

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

handle_call(check_status, _From, #state{status = Status} = State) -> 
    {reply, Status, State}; 
handle_call({echo, Msg}, _From, State) -> 
    io:format("~p get echo request for message ~p~n", [self(), Msg]), 
    {reply, Msg, State#state{status = done}}; 
handle_call(stop, _From, State) -> 
    {stop, normal, stopped, State}; 
handle_call(_Request, _From, State) -> 
    {noreply, State}. 

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

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

terminate(_Reason, _State) -> 
    ok. 

は、デザインは、それが要求を受信すると、それは仕事を終えた1一時的なプロセスを終了しますが、一時的な上司が開始されると3つの一時的なプロセスを開始することになっています。 error docsから

9> temp:start_link().  
****Main supervisor**** 
****Temp supervisor***** 
Start temporary worker process <0.98.0> 
{ok,<0.94.0>} 
Start temporary worker process <0.99.0> 
Start temporary worker process <0.101.0> 
10> temp_srv:echo_call(asd). 
Find available children <0.98.0> 
Start temporary worker process <0.102.0> 
Assign task to <0.98.0> 
<0.98.0> get echo request for message asd 
asd 
11> temp_srv:echo_call(asd). 
Find process <0.98.0> to kill 

=ERROR REPORT==== 23-May-2017::23:16:34 === 
** Generic server temp_srv terminating 
** Last message in was {echo,asd} 
** When Server state == {state} 
** Reason for termination == 
** {{noproc,{gen_server,call,[<0.98.0>,check_status]}}, 
    [{gen_server,call,2,[{file,"gen_server.erl"},{line,204}]}, 
    {temp_sup,select_available_children,1,[{file,"temp_sup.erl"},{line,41}]}, 
    {temp_sup,assign_task,1,[{file,"temp_sup.erl"},{line,33}]}, 
    {temp_srv,handle_call,3,[{file,"temp_srv.erl"},{line,21}]}, 
    {gen_server,try_handle_call,4,[{file,"gen_server.erl"},{line,615}]}, 
    {gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,647}]}, 
    {proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,247}]}]} 

=ERROR REPORT==== 23-May-2017::23:16:34 === 
** Generic server temp terminating 
** Last message in was {'EXIT',<0.92.0>, 
          {{{noproc, 
           {gen_server,call,[<0.98.0>,check_status]}}, 
          {gen_server,call,[temp_srv,{echo,asd}]}}, 
          [{gen_server,call,2, 
           [{file,"gen_server.erl"},{line,204}]}, 
          {erl_eval,do_apply,6, 
           [{file,"erl_eval.erl"},{line,674}]}, 
          {shell,exprs,7,[{file,"shell.erl"},{line,686}]}, 
          {shell,eval_exprs,7, 
           [{file,"shell.erl"},{line,641}]}, 
          {shell,eval_loop,3, 
           [{file,"shell.erl"},{line,626}]}]}} 
** When Server state == {state, 
          {local,temp}, 
          one_for_one, 
          [{child,<0.96.0>,temp_sup, 
           {temp_sup,start_link,[]}, 
           permanent,infinity,supervisor, 
           [temp_sup]}, 
          {child,<0.104.0>,temp_srv, 
           {temp_srv,start_link,[]}, 
           permanent,infinity,worker, 
           [temp_srv]}], 
          undefined,5,10, 
          [-576459529], 
          0,temp,[]} 
** Reason for termination == 
** {{{noproc,{gen_server,call,[<0.98.0>,check_status]}}, 
    {gen_server,call,[temp_srv,{echo,asd}]}}, 
    [{gen_server,call,2,[{file,"gen_server.erl"},{line,204}]}, 
    {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,674}]}, 
    {shell,exprs,7,[{file,"shell.erl"},{line,686}]}, 
    {shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]}, 
    {shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]} 
** exception exit: {{noproc,{gen_server,call,[<0.98.0>,check_status]}}, 
        {gen_server,call,[temp_srv,{echo,asd}]}} 
    in function gen_server:call/2 (gen_server.erl, line 204) 

答えて

0

::私はこれらのコードを実行する方法を説明します

noproc - 非既存のプロセスにリンクしようとしています。

エラーメッセージは、問題のラインは言う:

case gen_server:call(Pid, check_status) of 

PIDが存在しないプロセスであることを意味します。あなたの出力では、あなたが見ることができます:

Assign task to <0.98.0> 
<0.98.0> get echo request for message asd 
asd 

私は< 0.98.0>は、実行が完了したと終了したプロセスを意味だと思います。存在しないプロセスに対してundefinedを返すprocess_info(Pid)を出力することで確認できます。そのプロセスはChildLリストの先頭にあります。あなたはio:format()文であることを確認することができます。

assign_task(Data) -> 
     ... 
     case select_finished_children(ChildL) of 
      no_pid_to_kill -> ok; 
      {ok, KPid} -> gen_server:call(KPid, stop) 
     end, 
     io:format("assign_task(): ChildL: ~w~n", [ChildL]), %%<***HERE 
     io:format("****Info: ~w~n", [process_info(Pid)]), %%<***HERE 
     {ok, Pid} = select_available_children(ChildL), 

を次に、あなたのコードは、このん:

select_available_children([ChildH | ChildT]) -> 
    {undefined, Pid, worker, [temp_worker]} = ChildH, 
    case gen_server:call(Pid, check_status) of 

ChildHが終了したPID <0.98.0>を、含まれており、そのPIDがPidにバインドされます。その後、gen_server:call(Pid)が実行され、noprocというエラーが発生します。

+0

私はprocess_infoを使用してプロセスを確認しましたが、結果はプロセスがまだ生きていることを示し、そのステータスは待機しています。 – billcyz

+0

@billcyz、さあさあ。ステータスが待っていた後、エラーはありませんでした。 – 7stud

+0

いつプロセスをチェックしましたか? erlangがクラッシュした後でチェックした場合、何も見つからず、そのスーパーバイザは消えてしまいます。 – billcyz

関連する問題