Erlang -- gen_server

gen_server

gen_server是Erlang OTP中的通用服务器模板。
gen_serverbehavior函数和回调函数之间的关系如下:

gen_server module            Callback module
-----------------            ---------------
gen_server:start
gen_server:start_link -----> Module:init/1

gen_server:stop       -----> Module:terminate/2

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

通过gen_server:start(Module, Args, Options)gen_server:start(ServerName, Module, Args, Options)gen_server:start_link(Module, Args, Options)gen_server:start_link(ServerName, Module, Args, Options)启动一个gen_server进程,startstart_link的区别在于用start启动的进程相当于创建一个独立的进程,当需要在监控树中启动时,需要使用start_link
ServerName指定了进程的名字,格式可以是{local, Name},{global, Name}以及{via, Module, Name},可不指定;
Module指定了gen_sever进程的回调模块;
如果ServerName{local, Name},会通过register/2将进程注册为Name。为{global, Name}则通过global:register_name/2将进程注册为Name
Args会作为参数传递给Module:init(Args);
Options为其他可选项。
gen_server进程启动时会调用Module:init(Args)对进程数据进行初始化处理,如果成功则会返回{ok,State}|{ok,State,TimeOut}|{ok,State,hibernate}State为进程数据;TimeOut表示进程如果TimeOut ms内没有收到消息,将会触发一个超时,超时消息将会被Module:handle_info(timeout, State)处理;hibernate表示进程将会挂起直至下一个消息到来。启动失败则会返回{stop, Reason}ignore。由于start_link为同步调用,在init返回前它是不会返回的。

可以通过gen_server:stop(ServerRef)或stop(ServerRef, Reason, TimeOut)去结束一个gen_server进程。
gen_server进程在退出前会先调用Module:terminate(Reason, State)善后。ServerRefgen_server进程的Pid或进程名。

对于属于监控树的gen_server,需要满足在以下条件才会在进程终止前调用terminate/2:

  1. init中调用process_flag(trap_exit, true)
  2. 监控树设定的关闭策略被设定为一个超时值,而非直接kill掉。

不属于监控树时,当gen_server进程在收到父进程的'Exit'消息时也会调用该方法。

可以通过gen_server:call(ServerRef, Request)gen_server:call(ServerRef, Request, TimeOut)gen_server进程同步发送一个消息并等待返回,超过TimeOut(默认为5000) ms未返回则会导致调用失败。gen_server进程通过调用Module:handle_call(Request, From, State)处理该消息并返回{reply, Reply, NewState}Reply会返还给调用进程。

可以通过gen_server:cast(ServerRef, Request)gen_server进程异步发送一个消息并立即返回okgen_server进程通过调用Module:handle_cast(Request, State)处理该消息并返回{noreply, NewState}

另外,可以通过Pid!Info或者erlang:send(Pid, Info)gen_server进程发送消息,gen_server将会通过Module:handle_info(Info, State)来处理该消息。

一个简单gen_server模板(自《Erlang程序设计》)
-module(gen_server_mudule).
-behaviour(gen_server).
%% API
-export([start_link/0]).
%% gen_server回调函数
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). 
%%%===================================================================
%%% API
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% 启动服务器
%%
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link() ->
 gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
%%%===================================================================
%%% gen_server回调函数
%%%===================================================================
%%--------------------------------------------------------------------
%% @private
%% @doc
%% 初始化服务器
%%
%% @spec init(Args) -> {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% @end
%%--------------------------------------------------------------------
init([]) ->
 {ok, []}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% 处理调用消息
%%
%% @spec handle_call(Request, From, State) ->
%% {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_call(_Request, _From, State) ->
 Reply = ok,
 {reply, Reply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% 处理播发消息
%%
%% @spec handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @end
%%-------------------------------------------------------------------- 
handle_cast(_Msg, State) ->
 {noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% 处理所有非调用/播发的消息
%%
%% @spec handle_info(Info, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_info(_Info, State) ->
 {noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% 这个函数是在某个gen_server即将终止时调用的。它应当是Module:init/1的逆操作,并进行必要的清理。
%% 当它返回时,gen_server终止并生成原因Reason。它的返回值会被忽略
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
 ok.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% 在代码更改时转换进程状态
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
 {ok, State}.
%%%===================================================================
%%% 内部函数
%%%=================================================================== 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值