about gen_server

自带文档的简介:

A behaviour module for implementing the server of a client-server relation. A generic server process (gen_server) implemented using this module will have a standard set of interface functions and include functionality for tracing and error reporting. It will also fit into an OTP supervision tree. Refer to OTP Design Principles for more information.

A gen_server assumes all specific parts to be located in a callback module exporting a pre-defined set of functions. 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
%%handle_call(_Request,_From,State)->^^
%%gen_server中至少会涉及道3个线程,发起调用的客户端的进程的Pid(_From),State是默认的module:init->{ok,State}中返回的线程State(这个是默认的),
%%最后的一个是module的线程,即实际操作的线程
%%

gen_server:start_link(Name, Mod, InitArgs, Opts)创建一个名为Name的server,callback moudle为Mod
Mod:init(InitArgs)启动server
client端程序调用gen_server:call(Name, Request)来调用server,server处理逻辑为handle_call/3
gen_server:cast(Name, Name)调用callback handle_cast(_Msg, State)以改变server状态
handle_info(_Info, State)用来处理发给server的自发消息
terminate(_Reason, State)是server关闭时的callback
code_change是server热部署或代码升级时做callback修改进程状态
%%
 gen_server:cast gen_server:abcast -----> Module:handle_cast/2 - -----> Module:handle_info/2 - -----> Module:terminate/2 - -----> Module:code_change/3

If a callback function fails or returns a bad value, the gen_server will terminate.

A gen_server handles system messages as documented in sys(3). The sys module can be used for debugging a gen_server.

Note that a gen_server does not trap exit signals automatically, this must be explicitly initiated in the callback module.

Unless otherwise stated, all functions in this module fail if the specified gen_server does not exist or if bad arguments are given.

The gen_server process can go into hibernation (see erlang(3)) if a callback function specifies 'hibernate' instead of a timeout value. This might be useful if the server is expected to be idle for a long time. However this feature should be used with care as hibernation implies at least two garbage collections (when hibernating and shortly after waking up) and is not something you'd want to do between each call to a busy server.

%% ---

%% 这个是书中自带的简单例子
%%  Excerpted from "Programming Erlang",
%%  published by The Pragmatic Bookshelf.
%%  Copyrights apply to this code. It may not be used to create training material,
%%  courses, books, articles, and the like. Contact us if you are in doubt.
%%  We make no guarantees that this code is fit for any purpose.
%%  Visit http://www.pragmaticprogrammer.com/titles/jaerlang for more book information.
%%---
-module(my_bank).

-behaviour(gen_server).
-export([start/0]).
%% gen_server callbacks
-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, your_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}.


   

posted on 2011-05-15 09:14  songqiuming  阅读(770)  评论(0编辑  收藏  举报

导航