simple_one_for_one vs one_for_one:
相同點:
這種Restart Strategy和one_for_one基本相同(即當一個child process掛掉后,僅僅重啟該child process 而不影響其他child process)。
異同點:
1, simple_one_for_one supvisor啟動時不會啟動任何子進程,所有子進程都只能通過調用 supervisor:start_child(Sup, Args) 來動態啟動。
2, simple_one_for_one supvisor持有child process的定義,並有一個dict存放數據, 其實就是如干個child process,共享一份數據。
3, 一個simple_one_for_one supervisor只有一個(single)simple_one_for_one的定義, 也就是說它只能生產出一種類型worker process。
supervisor:start_child(Sup, Args) :
Sup: Supervisor的Pid或者registered Name.
Args: 當supervisor的類型是simple_one_for_one時,Args會追加到spec的參數中。
例如:
-module(simple_sup). -behaviour(supervisor). -export([start_link/0]). -export([init/1]). start_link() -> supervisor:start_link({local,?MODULE}, ?MODULE, []). init(_Args) -> {M, F, A} = _Args, {ok, {{simple_one_for_one, 0, 1}, [{M, {M, F, A}, temporary, brutal_kill, worker, [M]}]}}.
調用supervisor:start_child(simple_sup, Args)后,最終啟動子進程的代碼會是:apply(M, F, A++Args).
調用supervisor:start_child(Sup, Args)可能會遇到的錯誤:
1, noproc: 可能的原因是在調用supervisor:start_link時沒寫參數{local, ?MODULE},即上面代碼紅色部分,此時進程Sup並不存在,所以會產生
noproc錯誤。
2,undef: 可能的原因是A++Args后,與child process的start_link函數參數不一致。
實例代碼:
實例包含兩部分,一是監控普通進程(normal_process.erl),二是監控gen_server進程(gen_server_process.erl)。
common.hrl
%%-define(CALL, normal_process). -define(CALL, gen_server_process).
simple_sup.erl
-module(simple_sup). -behaviour(supervisor). -export([start_link/0]). -export([init/1]). -include("common.hrl"). start_link() -> supervisor:start_link({local, ?MODULE}, simple_sup, []). init(_Args) -> {ok, {{simple_one_for_one, 0, 1}, [{?CALL, {?CALL, start_link, []}, temporary, brutal_kill, worker, [?CALL]}]}}.
normal_process.erl
-module(normal_process). -export([start_link/0, start_loop/1]). start_link() -> proc_lib:start_link(?MODULE, start_loop, [self()]). start_loop(Parent) -> proc_lib:init_ack(Parent, {ok, self()}), loop(). loop() -> receive Args -> io:format("~p~n", [Args]) end.
gen_server_process.erl
-module(gen_server_process). -behaviour(gen_server). -export([start_link/0]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). %% interface -export([start/0, stop/0, echo/1]). %% interface implement start() -> start_link(). stop() -> gen_server:call(?MODULE, stop). echo(String) -> gen_server:call(?MODULE, {echo, String}). %% gen_server callbacks implement start_link() -> gen_server:start_link({local,?MODULE}, ?MODULE, [], []). init([]) -> {ok, 0}. handle_call({echo, String}, _From, Tab) -> Reply = String, {reply, Reply, Tab}; handle_call(stop, _From, Tab) -> {stop, normal, stopped, Tab}. handle_cast(_Msg, State) -> {noreply, State}. handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}.
編譯命令:
c(simple_sup).
c(normal_process).
c(gen_server_process).
測試命令:
simple_sup:start_link().
supervisor:start_child(simple_sup, []).
測試通過start_child啟動普通進程:
修改common.hrl:-define(CALL, normal_process). 執行編譯命令 + 測試命令。
測試通過start_child啟動gen_server進程:
修改common.hrl:-define(CALL, gen_server_process). 執行編譯命令 + 測試命令。