浏览 4890 次
锁定老帖子 主题:otp深入浅出之:gen_server
精华帖 (0) :: 良好帖 (19) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-04-22
最后修改:2009-05-05
what is the gen_server ?
man 中 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.
一个简单的echo gen_server -module(echo). -behaviour(gen_server). %% API -export([start_link/0]). -export([echo/1]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -record(state, {}). echo(Msg)-> gen_server:call(?MODULE,{echo , Msg} ). start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). init([]) -> {ok, #state{}}. handle_call({echo , Msg}, _From, State) -> {reply , Msg , State }; handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. %%其他自动生成部分省略 echo gen_server代码的主干可以由模板生成,具体请参google。 运行并测试echo gen_server echo:start_link(), echo:echo("hello world"). how to start a echo gen_server ? 如上图,在主进程中的调用顺序为:echo:start_link->gen_server:start_link->gen:start->proc_lib:start_link proc_lib:start_link中通过erlang:spawn_link创建echo进程,新进程中依次回调 gen:init_it->gen_server:init_it->echo:init,从而注入echo自己的初始化逻辑。 在gen_server:init_it中分析回调echo:init的返回值,初始化成功以后则进入循环。 init_it(Starter, Parent, Name, Mod, Args, Options) -> Debug = debug_options(Name, Options), case catch Mod:init(Args) of {ok, State} -> proc_lib:init_ack(Starter, {ok, self()}), loop(Parent, Name, State, Mod, infinity, Debug); {ok, State, Timeout} -> proc_lib:init_ack(Starter, {ok, self()}), loop(Parent, Name, State, Mod, Timeout, Debug); {stop, Reason} -> proc_lib:init_ack(Starter, {error, Reason}), exit(Reason); ignore -> proc_lib:init_ack(Starter, ignore), exit(normal); {'EXIT', Reason} -> proc_lib:init_ack(Starter, {error, Reason}), exit(Reason); Else -> Error = {bad_return_value, Else}, proc_lib:init_ack(Starter, {error, Error}), exit(Error) end. how to deal with a call ? gen_server:call({local,echo},{echo,"hello,world"}). gen_server:call调用gen:call发起一个同步的消息请求,使用标签"$gen_call"作为表示,表示这是应用的消息,不是系统的消息。 call(Name, Request) -> case catch gen:call(Name, '$gen_call', Request) of {ok,Res} -> Res; {'EXIT',Reason} -> exit({Reason, {?MODULE, call, [Name, Request]}}) end. 在主循环gen_server:loop中从消息队列中依次取出消息并处理,注意这是串行的,在一条消息处理完毕之前,不会处理下一条消息。 loop(Parent, Name, State, Mod, Time, Debug) -> Msg = receive Input -> Input after Time -> timeout end, decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, false). gen_server:decode_msg区分不同消息类型,分别处理 decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) -> case Msg of {system, From, Req} -> sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, [Name, State, Mod, Time], Hib); {'EXIT', Parent, Reason} -> terminate(Reason, Name, Msg, Mod, State, Debug); _Msg when Debug =:= [] -> handle_msg(Msg, Parent, Name, State, Mod); _Msg -> Debug1 = sys:handle_debug(Debug, {?MODULE, print_event}, Name, {in, Msg}), handle_msg(Msg, Parent, Name, State, Mod, Debug1) end. gen_server:handle_msg回调echo:handle_call处理应用信息,处理成功则返回loop方法。 handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod) -> case catch Mod:handle_call(Msg, From, State) of {reply, Reply, NState} -> reply(From, Reply), loop(Parent, Name, NState, Mod, infinity, []); {reply, Reply, NState, Time1} -> reply(From, Reply), loop(Parent, Name, NState, Mod, Time1, []); {noreply, NState} -> loop(Parent, Name, NState, Mod, infinity, []); {noreply, NState, Time1} -> loop(Parent, Name, NState, Mod, Time1, []); {stop, Reason, Reply, NState} -> {'EXIT', R} = (catch terminate(Reason, Name, Msg, Mod, NState, [])), reply(From, Reply), exit(R); Other -> handle_common_reply(Other, Parent, Name, Msg, Mod, State) end; how to deal with a cast ? how to deal with a info ? 要注意的地方 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-05-05
不错,实战派!
|
|
返回顶楼 | |
发表时间:2009-05-12
图不错 gen_server其实是很复杂的 在里面做了很多安全性和稳定性的工作 还支持调试 代码更新 全局名字 supervisor等等 这些功能我们能难自己去写的对 推荐用gen_server, 比较没有大的什么性能开销。
http://blog.yufeng.info |
|
返回顶楼 | |
发表时间:2009-11-16
级别不够,看不懂
|
|
返回顶楼 | |