Erlang supervisor/gen_server 异常退出:noproc
Erlang supervisor/gen_server exception exit: noproc
我现在快要疯了,想弄清楚这是什么问题。
基本上我只想用 1 个服务器和 1 个 gen_event-behaviour 模块设置一个简单的 Supervisor。
现在的问题是我再也无法启动它了,就是主管。
无论我做什么我都会得到这个错误:
** 异常退出:noproc
并且在使用文本跟踪器时它显示它发生在 sRPG_supervisor:init/1 中。有了这个你认为代码有问题,但是当我 运行 其他人的例子时我得到了完全相同的东西(我已经下载了 Joe Armstrongs 的例子并用相同的方法测试了 sellaprime_supervisor结果)。
当我在我的虚拟 Ubuntu 安装中 运行 它曾经启动良好。然后我设置它,这样我就可以在 Windows 中编写代码,但我什至从未测试过这种最简单的形式是否有效,显然由于某种原因它没有。
所以如果有人遇到过类似的问题,能找到解决方案会很棒!
我使用 erl6.3 作为带有 OTP 17 的 Erlang 版本。
这是我正在使用的代码,只是 Emacs 生成的框架的构建:
sRPG_supervisor.erl
-module(sRPG_supervisor).
-behaviour(supervisor).
%% API
-export([start_link/0, start_link/1, start/0, start_in_shell_for_testing/0]).
%% Supervisor callbacks
-export([init/1]).
-define(SERVER, ?MODULE).
%%%===================================================================
%%% API functions
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% Starts the supervisor
%%
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
start() ->
spawn(fun() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, _Arg = [])
end).
start_in_shell_for_testing() ->
{ok, Pid} = supervisor:start_link({local, ?SERVER}, ?MODULE, _Arg = []),
unlink(Pid).
start_link(Args) ->
supervisor:start_link({local, ?SERVER}, ?MODULE, Args).
%%%===================================================================
%%% Supervisor callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever a supervisor is started using supervisor:start_link/[2,3],
%% this function is called by the new process to find out about
%% restart strategy, maximum restart frequency and child
%% specifications.
%%
%% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} |
%% ignore |
%% {error, Reason}
%% @end
%%--------------------------------------------------------------------
init([]) ->
%% Install sRPG event/error handler
gen_event:swap_handler(alarm_handler, {alarm_handler, swap}, {sRPG_event_handler, xyz}),
RestartStrategy = one_for_one,
MaxRestarts = 1000,
MaxSecondsBetweenRestarts = 3600,
SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts},
Restart = permanent,
Shutdown = 2000,
Type = worker,
AChild = {sRPG_server, {sRPG_server, start_link, []},
Restart, Shutdown, Type, [sRPG_server]},
{ok, {SupFlags, [AChild]}}.
sRPG_server.erl
-module(sRPG_server).
-behaviour(gen_server).
%% API
-export([start_link/0, testServer/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {}).
%%%===================================================================
%%% API
%%%===================================================================
testServer() ->
gen_server:call(?MODULE, {test, test}).
%%--------------------------------------------------------------------
%% @doc
%% Starts the server
%%
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Initializes the server
%%
%% @spec init(Args) -> {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% @end
%%--------------------------------------------------------------------
init([]) ->
%% Note we must set trap_exit = true if we want
%% terminate/2 to be called when the application is stopped
process_flag(trap_exit, true),
%MainGamePid = gameSystem:start(),
io:format("~p starting~n", [?MODULE]),
{ok, #state{}}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling call messages
%%
%% @spec handle_call(Request, From, State) ->
%% {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_call({test, test}, _From, State) ->
io:format("TEST TEST TEST ~n"),
Reply = ok,
{reply, Reply, State};
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling cast messages
%%
%% @spec handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_cast(_Msg, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling all non call/cast messages
%%
%% @spec handle_info(Info, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_info(_Info, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ok.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Convert process state when code is changed
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%%===================================================================
%%% Internal functions
%%%===================================================================
sRPG_event_handler.erl
-module(sRPG_event_handler).
-behaviour(gen_event).
%% API
-export([start_link/0, add_handler/0]).
%% gen_event callbacks
-export([init/1, handle_event/2, handle_call/2,
handle_info/2, terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {}).
%%%===================================================================
%%% gen_event callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% Creates an event manager
%%
%% @spec start_link() -> {ok, Pid} | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link() ->
gen_event:start_link({local, ?SERVER}).
%%--------------------------------------------------------------------
%% @doc
%% Adds an event handler
%%
%% @spec add_handler() -> ok | {'EXIT', Reason} | term()
%% @end
%%--------------------------------------------------------------------
add_handler() ->
gen_event:add_handler(?SERVER, ?MODULE, []).
%%%===================================================================
%%% gen_event callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever a new event handler is added to an event manager,
%% this function is called to initialize the event handler.
%%
%% @spec init(Args) -> {ok, State}
%% @end
%%--------------------------------------------------------------------
init([]) ->
io:format("*** sRPG Event Handler init ***~n"),
{ok, #state{}};
init(Args) ->
io:format("*** sRPG Event Handler init: ~p~n", [Args]),
{ok, #state{}}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever an event manager receives an event sent using
%% gen_event:notify/2 or gen_event:sync_notify/2, this function is
%% called for each installed event handler to handle the event.
%%
%% @spec handle_event(Event, State) ->
%% {ok, State} |
%% {swap_handler, Args1, State1, Mod2, Args2} |
%% remove_handler
%% @end
%%--------------------------------------------------------------------
handle_event({set_alarm, testAlarm}, State) ->
error_logger:error_msg("*** BEEP BOOP TEST ALARM ***~n"),
{ok, State};
handle_event({clear_alarm, testAlarm}, State) ->
error_logger:error_msg("*** Brrrrppp... Test Alarm Over ***~n"),
{ok, State};
handle_event(_Event, State) ->
{ok, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever an event manager receives a request sent using
%% gen_event:call/3,4, this function is called for the specified
%% event handler to handle the request.
%%
%% @spec handle_call(Request, State) ->
%% {ok, Reply, State} |
%% {swap_handler, Reply, Args1, State1, Mod2, Args2} |
%% {remove_handler, Reply}
%% @end
%%--------------------------------------------------------------------
handle_call(_Request, State) ->
Reply = ok,
{ok, Reply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called for each installed event handler when
%% an event manager receives any other message than an event or a
%% synchronous request (or a system message).
%%
%% @spec handle_info(Info, State) ->
%% {ok, State} |
%% {swap_handler, Args1, State1, Mod2, Args2} |
%% remove_handler
%% @end
%%--------------------------------------------------------------------
handle_info(_Info, State) ->
{ok, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever an event handler is deleted from an event manager, this
%% function is called. It should be the opposite of Module:init/1 and
%% do any necessary cleaning up.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ok.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Convert process state when code is changed
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%%===================================================================
%%% Internal functions
%%%===================================================================
下面是发生的情况的示例:
Eshell V6.3 (abort with ^G)
1> sRPG_supervisor:start_link().
** exception exit: noproc
2> sRPG_supervisor:start_in_shell_for_testing().
** exception exit: noproc
3> ServPid = sRPG_server:start_link().
sRPG_server starting
{ok,<0.39.0>}
4> gen_server:call(sRPG_server, {test, test}).
TEST TEST TEST
ok
如您所见,在没有主管的情况下调用服务器时服务器可以正常工作。
我仔细查看了其他人遇到的类似问题,但无济于事。
除非 sasl
应用程序是 运行,否则 alarm_handler
也不会是 运行,并且 noproc
异常发生在您的主管 init
结果。试试这个:
1> application:start(sasl).
ok
2> sRPG_supervisor:start_in_shell_for_testing().
*** sRPG Event Handler init: {xyz,{alarm_handler,[]}}
sRPG_server starting
=PROGRESS REPORT==== 12-Aug-2015::17:00:49 ===
supervisor: {local,sRPG_supervisor}
started: [{pid,<0.71.0>},
{id,sRPG_server},
{mfargs,{sRPG_server,start_link,[]}},
{restart_type,permanent},
{shutdown,2000},
{child_type,worker}]
true
我现在快要疯了,想弄清楚这是什么问题。
基本上我只想用 1 个服务器和 1 个 gen_event-behaviour 模块设置一个简单的 Supervisor。
现在的问题是我再也无法启动它了,就是主管。
无论我做什么我都会得到这个错误: ** 异常退出:noproc
并且在使用文本跟踪器时它显示它发生在 sRPG_supervisor:init/1 中。有了这个你认为代码有问题,但是当我 运行 其他人的例子时我得到了完全相同的东西(我已经下载了 Joe Armstrongs 的例子并用相同的方法测试了 sellaprime_supervisor结果)。
当我在我的虚拟 Ubuntu 安装中 运行 它曾经启动良好。然后我设置它,这样我就可以在 Windows 中编写代码,但我什至从未测试过这种最简单的形式是否有效,显然由于某种原因它没有。
所以如果有人遇到过类似的问题,能找到解决方案会很棒! 我使用 erl6.3 作为带有 OTP 17 的 Erlang 版本。
这是我正在使用的代码,只是 Emacs 生成的框架的构建: sRPG_supervisor.erl
-module(sRPG_supervisor).
-behaviour(supervisor).
%% API
-export([start_link/0, start_link/1, start/0, start_in_shell_for_testing/0]).
%% Supervisor callbacks
-export([init/1]).
-define(SERVER, ?MODULE).
%%%===================================================================
%%% API functions
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% Starts the supervisor
%%
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
start() ->
spawn(fun() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, _Arg = [])
end).
start_in_shell_for_testing() ->
{ok, Pid} = supervisor:start_link({local, ?SERVER}, ?MODULE, _Arg = []),
unlink(Pid).
start_link(Args) ->
supervisor:start_link({local, ?SERVER}, ?MODULE, Args).
%%%===================================================================
%%% Supervisor callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever a supervisor is started using supervisor:start_link/[2,3],
%% this function is called by the new process to find out about
%% restart strategy, maximum restart frequency and child
%% specifications.
%%
%% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} |
%% ignore |
%% {error, Reason}
%% @end
%%--------------------------------------------------------------------
init([]) ->
%% Install sRPG event/error handler
gen_event:swap_handler(alarm_handler, {alarm_handler, swap}, {sRPG_event_handler, xyz}),
RestartStrategy = one_for_one,
MaxRestarts = 1000,
MaxSecondsBetweenRestarts = 3600,
SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts},
Restart = permanent,
Shutdown = 2000,
Type = worker,
AChild = {sRPG_server, {sRPG_server, start_link, []},
Restart, Shutdown, Type, [sRPG_server]},
{ok, {SupFlags, [AChild]}}.
sRPG_server.erl
-module(sRPG_server).
-behaviour(gen_server).
%% API
-export([start_link/0, testServer/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {}).
%%%===================================================================
%%% API
%%%===================================================================
testServer() ->
gen_server:call(?MODULE, {test, test}).
%%--------------------------------------------------------------------
%% @doc
%% Starts the server
%%
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Initializes the server
%%
%% @spec init(Args) -> {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% @end
%%--------------------------------------------------------------------
init([]) ->
%% Note we must set trap_exit = true if we want
%% terminate/2 to be called when the application is stopped
process_flag(trap_exit, true),
%MainGamePid = gameSystem:start(),
io:format("~p starting~n", [?MODULE]),
{ok, #state{}}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling call messages
%%
%% @spec handle_call(Request, From, State) ->
%% {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_call({test, test}, _From, State) ->
io:format("TEST TEST TEST ~n"),
Reply = ok,
{reply, Reply, State};
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling cast messages
%%
%% @spec handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_cast(_Msg, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling all non call/cast messages
%%
%% @spec handle_info(Info, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_info(_Info, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ok.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Convert process state when code is changed
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%%===================================================================
%%% Internal functions
%%%===================================================================
sRPG_event_handler.erl
-module(sRPG_event_handler).
-behaviour(gen_event).
%% API
-export([start_link/0, add_handler/0]).
%% gen_event callbacks
-export([init/1, handle_event/2, handle_call/2,
handle_info/2, terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {}).
%%%===================================================================
%%% gen_event callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% Creates an event manager
%%
%% @spec start_link() -> {ok, Pid} | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link() ->
gen_event:start_link({local, ?SERVER}).
%%--------------------------------------------------------------------
%% @doc
%% Adds an event handler
%%
%% @spec add_handler() -> ok | {'EXIT', Reason} | term()
%% @end
%%--------------------------------------------------------------------
add_handler() ->
gen_event:add_handler(?SERVER, ?MODULE, []).
%%%===================================================================
%%% gen_event callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever a new event handler is added to an event manager,
%% this function is called to initialize the event handler.
%%
%% @spec init(Args) -> {ok, State}
%% @end
%%--------------------------------------------------------------------
init([]) ->
io:format("*** sRPG Event Handler init ***~n"),
{ok, #state{}};
init(Args) ->
io:format("*** sRPG Event Handler init: ~p~n", [Args]),
{ok, #state{}}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever an event manager receives an event sent using
%% gen_event:notify/2 or gen_event:sync_notify/2, this function is
%% called for each installed event handler to handle the event.
%%
%% @spec handle_event(Event, State) ->
%% {ok, State} |
%% {swap_handler, Args1, State1, Mod2, Args2} |
%% remove_handler
%% @end
%%--------------------------------------------------------------------
handle_event({set_alarm, testAlarm}, State) ->
error_logger:error_msg("*** BEEP BOOP TEST ALARM ***~n"),
{ok, State};
handle_event({clear_alarm, testAlarm}, State) ->
error_logger:error_msg("*** Brrrrppp... Test Alarm Over ***~n"),
{ok, State};
handle_event(_Event, State) ->
{ok, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever an event manager receives a request sent using
%% gen_event:call/3,4, this function is called for the specified
%% event handler to handle the request.
%%
%% @spec handle_call(Request, State) ->
%% {ok, Reply, State} |
%% {swap_handler, Reply, Args1, State1, Mod2, Args2} |
%% {remove_handler, Reply}
%% @end
%%--------------------------------------------------------------------
handle_call(_Request, State) ->
Reply = ok,
{ok, Reply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called for each installed event handler when
%% an event manager receives any other message than an event or a
%% synchronous request (or a system message).
%%
%% @spec handle_info(Info, State) ->
%% {ok, State} |
%% {swap_handler, Args1, State1, Mod2, Args2} |
%% remove_handler
%% @end
%%--------------------------------------------------------------------
handle_info(_Info, State) ->
{ok, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever an event handler is deleted from an event manager, this
%% function is called. It should be the opposite of Module:init/1 and
%% do any necessary cleaning up.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ok.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Convert process state when code is changed
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%%===================================================================
%%% Internal functions
%%%===================================================================
下面是发生的情况的示例:
Eshell V6.3 (abort with ^G)
1> sRPG_supervisor:start_link().
** exception exit: noproc
2> sRPG_supervisor:start_in_shell_for_testing().
** exception exit: noproc
3> ServPid = sRPG_server:start_link().
sRPG_server starting
{ok,<0.39.0>}
4> gen_server:call(sRPG_server, {test, test}).
TEST TEST TEST
ok
如您所见,在没有主管的情况下调用服务器时服务器可以正常工作。
我仔细查看了其他人遇到的类似问题,但无济于事。
除非 sasl
应用程序是 运行,否则 alarm_handler
也不会是 运行,并且 noproc
异常发生在您的主管 init
结果。试试这个:
1> application:start(sasl).
ok
2> sRPG_supervisor:start_in_shell_for_testing().
*** sRPG Event Handler init: {xyz,{alarm_handler,[]}}
sRPG_server starting
=PROGRESS REPORT==== 12-Aug-2015::17:00:49 ===
supervisor: {local,sRPG_supervisor}
started: [{pid,<0.71.0>},
{id,sRPG_server},
{mfargs,{sRPG_server,start_link,[]}},
{restart_type,permanent},
{shutdown,2000},
{child_type,worker}]
true