尝试终止子进程时Erlang noproc错误

时间:2017-05-24 06:17:56

标签: 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.

一旦临时主管启动,设计应该启动三个临时过程,一旦收到请求,它将终止一个已完成工作的临时过程。

我是如何运行这些代码的:

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)

1 个答案:

答案 0 :(得分:1)

来自error docs

  

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

我认为这意味着过程&lt; 0.98.0&gt;已完成执行并已终止。您可以输出process_info(Pid)来验证这一点,undefined将返回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

<0.98.0>包含已终止的pid Pid,并且该pid已绑定到gen_server:call(Pid)。然后执行noproc,这会导致client_max_body_size错误。