使用erlang:link链接来创建链接,并利用异常捕获来检测进程状态的变化
-module(gen_server1).
-behaviour(gen_server).
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3,stop/0,check/0]).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init(_Args) ->
erlang:link(whereis(gen_server2)),
{ok, []}.
handle_call(crash, _From, State) ->
%% 当接收到 crash 消息时,使 gen_server1 崩溃
io:format("gen_server1 crash~n"),
exit(normal),
{reply, ok, State};
handle_call(_Request, _From, State) ->
{reply, ok, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _ServerState) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%使gen_server1崩溃
stop() -> gen_server:call(?MODULE,crash).
%%检查gen_server2是否崩溃
check() ->
case whereis(gen_server2) of
undefined -> io:format("gen_server2 has crashed~n");
Pid -> io:format("gen_server2 is running pid is: ~p~n", [Pid])
end.
-module(gen_server2).
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init(_Args) ->
{ok, []}.
handle_call(_Request, _From, State) ->
{reply, ok, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info({'EXIT', _Pid, normal}, State) ->
{noreply, State};
handle_info({'EXIT', _Pid, Reason}, State) ->
%% gen_server1 崩溃,gen_server2 进行崩溃
exit(Reason),
{noreply, State}.
terminate(_Reason, _ServerState) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
代码运行截图
用定时器实现
-module(gen_server1).
-behaviour(gen_server).
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3, stop/0, check/0]).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init(_Args) ->
reset_timer(),
{ok, []}.
handle_call(crash, _From, State) ->
%% 当接收到 crash 消息时,使 gen_server1 崩溃
io:format("gen_server1 crash~n"),
exit(normal),
{reply, ok, State};
handle_call(_Request, _From, State) ->
{reply, ok, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(msg, State) ->
io:format("gen_server1 send msg~n"),
gen_server:cast(whereis(gen_server2),msg),
timer:sleep(5000),
reset_timer(),
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
reset_timer() ->
timer:send_after(5000, ?MODULE, msg).
terminate(_Reason, _ServerState) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
stop() -> gen_server:call(?MODULE, crash).
check() ->
case whereis(gen_server2) of
undefined -> io:format("gen_server2 has crashed~n");
Pid -> io:format("gen_server2 is running pid is: ~p~n", [Pid])
end.
-module(gen_server2).
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init(_Args) ->
reset_timer(),
{ok, []}.
handle_call(_Request, _From, State) ->
{reply, ok, State}.
handle_cast(msg, State) ->
%% 当接收到消息时,重置计时器
io:format("gen_server2 get msg"),
reset_timer(),
{noreply, State};
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(timeout, State) ->
%% 当超时未收到消息时,使 gen_server2 崩溃
io:format("gen_server2 timeout~n"),
exit(normal),
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
reset_timer() ->
timer:send_after(20000, ?MODULE, timeout).
terminate(_Reason, _ServerState) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.