原创作者: hideto
阅读:2062次
评论:1条
更新时间:2011-06-01
OTP Design Principles: Gen_Server Behaviour
1,Client-Server原则
client-server模型由一个中心服务器和任意多的客户端组成
该模型主要用来做资源管理操作,不同的客户端共享一个通用的资源,服务器负责管理该资源
2,例子
3,启动Gen_Server
ch3:start_link():
gen_server:start_link/4启动一个新进程并连接它,新进程为一个gen_server
1)第一个参数指定gen_server名字,{local, ch3}表示在本地注册一个gen_server进程为ch3
2)第二个参数指定callback module为ch3,在这里接口方法和callback方法都放在一个module里,这是一个好的编程实践
3)第三个参数指定init方法的参数
4)第四个参数为options
如果名字注册成功,新的gen_server进程调用callback方法ch3:init([]),返回{ok, State}
gen_server:start_link是同步的,直到gen_server初始化并且可以接收请求才返回,gen_server:start_link由supervisor启动,它是supervision tree的一部分
gen_server:start启动一个单独的进程,gen_server:start不是supervision tree的一部分,它没有supervisor
4,同步请求——Call
同步请求alloc()由gen_server:call/2实现:
ch3是gen_server的名字,alloc是实际的请求
该请求会发送一条消息给gen_server,请求接受以后,gen_server调用handle_call(Request, From, State)并返回{replay, Replay, State1}
5,异步请求——Cast
异步请求free(Ch)由gen_server:cast/2实现
ch3是gen_server的名字,{free, Ch}是真正的请求
callback方法为handle_cast(Request, State),返回{noreply, State1}.
6,关闭
6.1 在Supervision Tree中
如果gen_server是supervision tree的一部分,则不需要stop方法。gen_server会被supervisor自动关掉。
如果需要在关闭gen_server之前做清理工作,那么shutdown strategy必须为一个timeout并且必须在gen_server的init方法中设置捕获exit信号
gen_server将在关闭时调用callback方法terminate(shutdown, State):
6.2 单独的Gen_Servers
如果gen_server不是supervision tree的一部分,那么定义一个stop方法会比较有用:
callback方法处理stop请求,然后返回{stop, normal, State1},norma指定这是一个正常的关闭,State1为gen_server的state的新的值
这将使得gen_server调用terminate(normal, State1),然后优雅的关闭服务器
7,处理其他消息
如果gen_server可以接受除了请求外的其他消息,那么callback方法handle_info(Info, State)必须实现来处理它们
例如gen_server连接到supervisor以为的其他进程并捕获到exit信号,这时就会接受一个exit消息
补充:gen_server exports and callbacks
1,Client-Server原则
client-server模型由一个中心服务器和任意多的客户端组成
该模型主要用来做资源管理操作,不同的客户端共享一个通用的资源,服务器负责管理该资源
2,例子
-module(ch3). -behaviour(gen_server). -export([start_link/0]). -export([alloc/0, free/1]). -export([init/1, handle_call/3, handle_cast/2]). start_link() -> gen_server:start_link({local, ch3}, ch3, [], []). alloc() -> gen_server:call(ch3, alloc). free(Ch) -> gen_server:cast(ch3, {free, Ch}). init(_Args) -> {ok, channels()}. handle_call(alloc, _From, Chs) -> {Ch, Chs2} = alloc(Chs), {reply, Ch, Chs2}. handle_cast({free, Ch}, Chs) -> Chs2 = free(Ch, Chs), {noreply, Chs2}.
3,启动Gen_Server
ch3:start_link():
start_link() -> gen_server:start_link({local, ch3}, ch3, [], []) => {ok, Pid}
gen_server:start_link/4启动一个新进程并连接它,新进程为一个gen_server
1)第一个参数指定gen_server名字,{local, ch3}表示在本地注册一个gen_server进程为ch3
2)第二个参数指定callback module为ch3,在这里接口方法和callback方法都放在一个module里,这是一个好的编程实践
3)第三个参数指定init方法的参数
4)第四个参数为options
如果名字注册成功,新的gen_server进程调用callback方法ch3:init([]),返回{ok, State}
gen_server:start_link是同步的,直到gen_server初始化并且可以接收请求才返回,gen_server:start_link由supervisor启动,它是supervision tree的一部分
gen_server:start启动一个单独的进程,gen_server:start不是supervision tree的一部分,它没有supervisor
4,同步请求——Call
同步请求alloc()由gen_server:call/2实现:
alloc() -> gen_server:call(ch3, alloc).
ch3是gen_server的名字,alloc是实际的请求
该请求会发送一条消息给gen_server,请求接受以后,gen_server调用handle_call(Request, From, State)并返回{replay, Replay, State1}
5,异步请求——Cast
异步请求free(Ch)由gen_server:cast/2实现
free(Ch) -> gen_server:cast(ch3, {free, Ch}).
ch3是gen_server的名字,{free, Ch}是真正的请求
callback方法为handle_cast(Request, State),返回{noreply, State1}.
6,关闭
6.1 在Supervision Tree中
如果gen_server是supervision tree的一部分,则不需要stop方法。gen_server会被supervisor自动关掉。
如果需要在关闭gen_server之前做清理工作,那么shutdown strategy必须为一个timeout并且必须在gen_server的init方法中设置捕获exit信号
gen_server将在关闭时调用callback方法terminate(shutdown, State):
init(Args) -> ..., process_flag(trap_exit, true), ..., {ok, State}. ... terminate(shutdown, State) -> ..code for cleaning up here.. ok.
6.2 单独的Gen_Servers
如果gen_server不是supervision tree的一部分,那么定义一个stop方法会比较有用:
... export([stop/0]). ... stop() -> gen_server:cast(ch3, stop). ... handle_cast(stop, State) -> {stop, normal, State}; handle_cast({free, Ch}, State) -> ... ... terminate(normal, State) -> ok.
callback方法处理stop请求,然后返回{stop, normal, State1},norma指定这是一个正常的关闭,State1为gen_server的state的新的值
这将使得gen_server调用terminate(normal, State1),然后优雅的关闭服务器
7,处理其他消息
如果gen_server可以接受除了请求外的其他消息,那么callback方法handle_info(Info, State)必须实现来处理它们
例如gen_server连接到supervisor以为的其他进程并捕获到exit信号,这时就会接受一个exit消息
handle_info({'EXIT', Pid, Reason}, State) -> ..code to handle exits here.. {noreply, State1}.
补充:gen_server exports and callbacks
gen_server module callback module gen_server:start_link -------> Module:init/1 gen_server:start gen_server:call -------------> Module:handle_call/3 gen_server:multi_call gen_server:cast -------------> Module:handle_cast/2 gen_server:abcast gen_server:replay gen_server:enter_loop Module:handle_info/2 Module:terminate/2 Module:code_change/3
1 楼 ariestiger 2009-11-16 16:02
问一句:
是不是这样的?
我写了-behaviour(gen_server).
然后我实现那几个回调函数:
init/1;handle_call/3;handle_cast/2;handle_info/2;terminate/2;code_change/3
然后我在自己的业务方法,也就是提供给用户使用(你叫用户接口还是什么都行吧)的那些个方法中去调用gen_server:start_link或者gen_server:call或者gen_server:cast这些方法来间接调用我的那些回调方法对吧?从而将我的那些业务置于gen_server这种behivor中,对吧?
还有个问题。如果是像我上面说的那样的话,那我写的我感觉更像工作都,不像监督者啊?监督我总感觉应该是由服务器监督,那也就是由 gen_server来监督了。
现在学这玩意感觉在这里绕来绕去的,好多代码把个方法名字取得太像了,分不清那些是要主动调用,哪些是被系统回调的,一看头就大了。
就这两个问题,望楼主和其他的同行们要是能解答,请帮个忙,搭把手,谢谢了!