gen_server的源代码在C:\Program Files\erl5.7.3\lib\stdlib-1.16.3\src\gen_server.erl
The relationship between the behaviour functions and the callback functions can
be illustrated as follows:行为函数和回调函数的关系
gen_server module Callback module
----------------- ---------------
gen_server:start_link -----> Module:init/1
gen_server:call
gen_server:multi_call -----> Module:handle_call/3
gen_server:cast
gen_server:abcast -----> Module:handle_cast/2
- -----> Module:handle_info/2
- -----> Module:terminate/2
- -----> Module:code_change/3
%%% The work flow (of the server) can be described as follows:
%%%
%%% User module Generic
%%% ----------- -------
%%% start -----> start
%%% init <----- .
%%%
%%% loop
%%% handle_call <----- .
%%% -----> reply
%%%
%%% handle_cast <----- .
%%%
%%% handle_info <----- .
%%%
%%% terminate <----- .
%%%
%%% -----> reply
%%%
%%%
%%% ---------------------------------------------------
gen_fsm module Callback module
-------------- ---------------
gen_fsm:start_link -----> Module:init/1
gen_fsm:send_event -----> Module:StateName/2
gen_fsm:send_all_state_event -----> Module:handle_event/3
gen_fsm:sync_send_event -----> Module:StateName/3
gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
- -----> Module:handle_info/3
- -----> Module:terminate/3
- -----> Module:code_change/4
%%% The work flow (of the fsm) can be described as follows:
%%%
%%% User module fsm
%%% ----------- -------
%%% start -----> start
%%% init <----- .
%%%
%%% loop
%%% StateName <----- .
%%%
%%% handle_event <----- .
%%%
%%% handle__sunc_event <----- .
%%%
%%% handle_info <----- .
%%%
%%% terminate <----- .
%%%
%%%
%%% ---------------------------------------------------
gen_event module Callback module
--------------- -------------
gen_event:start_link -----> -
gen_event:add_handler
gen_event:add_sup_handler -----> Module:init/1
gen_event:notify
gen_event:sync_notify -----> Module:handle_event/2
gen_event:call -----> Module:handle_call/2
- -----> Module:handle_info/2
gen_event:delete_handler -----> Module:terminate/2
gen_event:swap_handler
gen_event:swap_sup_handler -----> Module1:terminate/2
Module2:init/1
gen_event:which_handlers -----> -
gen_event:stop -----> Module:terminate/2
- -----> Module:code_change/3
-module(server4).
-export([start/2,rpc/2, swap_code/2]).
start(Name, Mod) ->
register(Name,
spawn(fun() -> loop(Name, Mod, Mod:init()) end)).
swap_code(Name, Mod) ->rpc(Name, {swap_code, NewMod}).rpc(Name, Request) ->
Name ! {self(), Request},
receive
{Name, crash} ->exit(rpc); {Name, ok, Response} ->Response
end.
loop(Name, Mod, State) ->
receive
{From, {swap_code,NewCallbackMod}} -> From!{Name,ok,ack},
loop(Name, NewCallbackMod, OldState); {From, Request} ->
try Mod:handle(Request, OldState) of
{Response, NewState} ->
From ! {Name,ok, Response},
loop(Name, Mod, NewState)
catch
_:Why ->
log_the_error(Name, Request, Why),
From ! {Name, crash}, loop(Name, Mod, OldState)
end
end.
log_the_error(Name, Request, Why) ->
io:format("Server ~p request ~p~n"
"caused exception ~p~n",[Name, Request,Why]).
------------------------------------------------------------------------
-module(name_server1).
-export([init/0, add/2, whereis/1, handle/2]).
-import(server3, [rpc/2]).
%%client routines
add(Name, Place) -> rpc(name_server, {add, Name, Place}).
whereis(Name) -> rpc(name_server, {whereis, Name}).
%%callback routines
init() -> dict:new().
handle({add,Name, Place}, Dict) ->{ok, dict:store(Name, Place, Dict)};
handle({whereis, Name}, Dict) ->{dict:find(Name, Dict), Dict}.
---------------------------------------------------------------------------
1>server3:start(name_server, name_server1).
2>name_server:add(joe, "at home").
3>name_server:whereis(joe).
---------------------------------------------------------------------------
gen_server:start_link(,Mod,,) 会回调Mod:init().
%
-module(my_bank).
-behaviour(gen_server).
-export([start/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-compile(export_all).
start() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
stop() -> gen_server:call(?MODULE, stop).
new_account(Who) -> gen_server:call(?MODULE, {new, Who}).
deposit(Who, Amount) -> gen_server:call(?MODULE, {add, Who, Amount}).
withdraw(Who, Amount) -> gen_server:call(?MODULE, {remove, Who, Amount}).
init([]) ->{ok, ets:new(?MODULE, [])}.
handle_call({new, Who}, _From, Tab) ->
Reply = case ets:lookup(Tab, Who) of
[] -> ets:insert(Tab, {Who, 0}),
{welcome, Who};
[_] -> {Who, you_already_are_a_customer}
end,
{reply, Reply, Tab};
handle_call({add, Who, X}, _From, Tab) ->
Reply = case ets:lookup(Tab, Who) of
[] -> not_a_customer;
[{Who, Balance}] ->
NewBalance = Balance + X,
ets:insert(Tab, {Who, NewBalance}),
{thanks, Who, your_balance_is, NewBalance}
end,
{reply, Reply, Tab};
handle_call({remove,Who,X}, _From, Tab) ->
Reply = case ets:lookup(Tab, Who) of
[] -> not_a_customer;
[{Who,Balance}] when X =< Balance ->
NewBalance = Balance -X,
ets:insert(Tab, {Who, NewBalance}),
{thanks, Who, you_balance_is, NewBalance};
[{Who, Balance}] ->
{sorry, Who, you_only_have, Balance, in_the_bank}
end,
{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}.