Erlang gen_server:如何捕获错误?
Erlang gen_server: How to catch Errors?
我是 Erlang 开发的新手,我对进程关系很感兴趣。
如果我们 link 两个进程 P1 和 P2 process_flag(trap_exit, true)
并使用像 Pid ! msg
和 receive .. after .. end
这样的构造 - 有可能捕获像 [=17= 这样的 P1 错误] 由第二个进程 P2.
但是如果我们使用 gen_server
进程 P1,它与 P2 linked,- P1 在 P2 失败后终止。
那么,如何使用 gen_server 捕获 exit()
错误?
提前致谢!
P.S。测试代码。
P1:
-module(test1).
-compile(export_all).
-behaviour(gen_server).
start() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) -> Link = self(),
spawn(fun() ->
process_flag(trap_exit, true),
link(Link),
test2:start(Link)
end),
{ok, "lol"}.
handle_call(stop, From, State) ->
io:fwrite("Stop from ~p. State = ~p~n",[From, State]),
{stop, normal, "stopped", State};
handle_call(MSG, From, State) ->
io:fwrite("MSG ~p from ~p. State = ~p~n",[MSG, From, State]),
{reply, "okay", State}.
handle_info(Info, State) -> io:fwrite("Info message ~p. State = ~p~n",[Info, State]), {noreply, State}.
terminate(Reason, State) -> io:fwrite("Reason ~p. State ~p~n",[Reason, State]), ok.
P2:
-module(test2).
-compile(export_all).
start(Mod) ->
io:fwrite("test2: Im starting with Pid=~p~n",[self()]),
receiver(Mod).
receiver(Mod)->
receive
stop ->
Mod ! {goodbye},
io:fwrite("Pid: I exit~n"),
exit(badarith);
X ->
io:fwrite("Pid: I received ~p~n",[X])
end.
结果:test1 进程在 test2 以 badarith 退出后失败。
38>
38> c(test1).
test1.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,test1}
39> c(test2).
test2.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,test2}
40> test1:start().
test2: Im starting with Pid=<0.200.0>
{ok,<0.199.0>}
41> <0.200.0> ! stop.
Pid: I exit
Info message {goodbye}. State = "lol"
stop
** exception exit: badarith
42> gen_server:call(test1, stop).
** exception exit: {noproc,{gen_server,call,[test1,stop]}}
in function gen_server:call/2 (gen_server.erl, line 215)
43>
链接是双向的,但陷阱出口不是;您需要在 P1 中调用 process_flag(trap_exit, true)
(您当前的代码在 P2 中执行),然后在 handle_info
中处理形式为 {'EXIT', FromPid, Reason}
的消息(将 P2 的 pid 放入 State
以帮助)。
在这种情况下,如果 P1 停止,P2 停止是有意义的,否则我建议使用 monitor 而不是 link。
旁注:
使用spawn_link
代替spawn
+link
。
将spawn
移动到test2:start
是更好的风格。
我是 Erlang 开发的新手,我对进程关系很感兴趣。
如果我们 link 两个进程 P1 和 P2 process_flag(trap_exit, true)
并使用像 Pid ! msg
和 receive .. after .. end
这样的构造 - 有可能捕获像 [=17= 这样的 P1 错误] 由第二个进程 P2.
但是如果我们使用 gen_server
进程 P1,它与 P2 linked,- P1 在 P2 失败后终止。
那么,如何使用 gen_server 捕获 exit()
错误?
提前致谢!
P.S。测试代码。
P1:
-module(test1).
-compile(export_all).
-behaviour(gen_server).
start() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) -> Link = self(),
spawn(fun() ->
process_flag(trap_exit, true),
link(Link),
test2:start(Link)
end),
{ok, "lol"}.
handle_call(stop, From, State) ->
io:fwrite("Stop from ~p. State = ~p~n",[From, State]),
{stop, normal, "stopped", State};
handle_call(MSG, From, State) ->
io:fwrite("MSG ~p from ~p. State = ~p~n",[MSG, From, State]),
{reply, "okay", State}.
handle_info(Info, State) -> io:fwrite("Info message ~p. State = ~p~n",[Info, State]), {noreply, State}.
terminate(Reason, State) -> io:fwrite("Reason ~p. State ~p~n",[Reason, State]), ok.
P2:
-module(test2).
-compile(export_all).
start(Mod) ->
io:fwrite("test2: Im starting with Pid=~p~n",[self()]),
receiver(Mod).
receiver(Mod)->
receive
stop ->
Mod ! {goodbye},
io:fwrite("Pid: I exit~n"),
exit(badarith);
X ->
io:fwrite("Pid: I received ~p~n",[X])
end.
结果:test1 进程在 test2 以 badarith 退出后失败。
38>
38> c(test1).
test1.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,test1}
39> c(test2).
test2.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,test2}
40> test1:start().
test2: Im starting with Pid=<0.200.0>
{ok,<0.199.0>}
41> <0.200.0> ! stop.
Pid: I exit
Info message {goodbye}. State = "lol"
stop
** exception exit: badarith
42> gen_server:call(test1, stop).
** exception exit: {noproc,{gen_server,call,[test1,stop]}}
in function gen_server:call/2 (gen_server.erl, line 215)
43>
链接是双向的,但陷阱出口不是;您需要在 P1 中调用 process_flag(trap_exit, true)
(您当前的代码在 P2 中执行),然后在 handle_info
中处理形式为 {'EXIT', FromPid, Reason}
的消息(将 P2 的 pid 放入 State
以帮助)。
在这种情况下,如果 P1 停止,P2 停止是有意义的,否则我建议使用 monitor 而不是 link。
旁注:
使用
spawn_link
代替spawn
+link
。将
spawn
移动到test2:start
是更好的风格。