gen_server的enter_loop分析
http://my.oschina.net/astute/blog/119250?p=1
在看ranch user guide的过程中,发现实现protocol handler需要使用特殊的gen_server形式,也就是enter_loop函数调用,事例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
-module(echo_protocol). -behaviour(ranch_protocol). - export ([start_link/4]). - export ([init/4]). start_link(ListenerPid, Socket, Transport, Opts) -> Pid = spawn_link(?MODULE, init, [ListenerPid, Socket, Transport, Opts]), {ok, Pid}. init(ListenerPid, Socket, Transport, _Opts = []) -> ok = ranch:accept_ack(ListenerPid), loop(Socket, Transport). loop(Socket, Transport) -> case Transport:recv(Socket, 0, 5000) of {ok, Data} -> Transport:send(Socket, Data), loop(Socket, Transport); _ -> ok = Transport:close(Socket) end. |
实现ranch的protocol handler只需要实现start_link函数即可,函数中需要启动一个新的进程,新的进程需要调用accept_ack函数来绑定socket的owner进程。
如果回调要实现gen_server行为模式的话,Listener进程调用模块的start_link方法,内部同步的启动gen_server进程,并且等待gen_server进程调用init函数返回,如果这个时候在init的方法中调用accept_ack方法,就会造成循环调用,造成死锁。
ranch提供的方法如下,使用gen_server的enter_loop方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
-module(my_protocol). -behaviour(gen_server). -behaviour(ranch_protocol). - export ([start_link/4]). - export ([init/1]). %% Exports of other gen_server callbacks here. start_link(ListenerPid, Socket, Transport, Opts) -> proc_lib:start_link(?MODULE, [[ListenerPid, Socket, Transport, Opts]]). init(ListenerPid, Socket, Transport, _Opts = []) -> ok = proc_lib:init_ack({ok, self()}), %% Perform any required state initialization here. ok = ranch:accept_ack(ListenerPid), ok = Transport:setopts(Socket, [{active, once}]), gen_server:enter_loop(?MODULE, [], {state, Socket, Transport}). %% Other gen_server callbacks here. |
通常情况下启动gen_server,需要调用gen_server:start_link(),参数中设置回调模块,这样的话像上面的分析,是会有死锁的问题的。
规避这个问题就是使用enter_loop方法。这个方法可以让已经存在的独立进程成为gen_server进程,在进入普通的gen_server循环之前执行设定的逻辑。
Listener进程调用proc_lib:start_link方法,创建新进程A,A执行init方法,调用proc_lib:init_ack()方法,告诉listener进程A进程已经启动,此时Listener进程就可以返回了。然后A进程再执行accept_ack()方法,最后调用enter_loop方法,让自己进入gen_server的执行循环。
最新文章
- Beennan的内嵌汇编指导(译)Brennan's Guide to Inline Assembly
- HTML 的 <;div>; 和 <;span>; 标签
- hdu 1021
- Gym 100285G Cipher Message 3
- I Love This Game 2115(结构体)
- 去掉所有的html标签,得到HTML标签中的所有内容
- jquery for循环
- 【LeetCode每天一题】Simplify Path(简化路径)
- Android中getDrawable和getColor过时的替代方法
- Shiro入门 - 通过ini文件进行认证
- 织梦移动版页面点击下一篇获取不到id
- SpringCloud系列三:SpringSecurity 安全访问(配置安全验证、服务消费端处理、无状态 Session 配置、定义公共安全配置程序类)
- jq select 一些操作
- HSmartWindowControl 之 摄像头实时显示( 使用 WPF )
- Window系统 安装TFLearn
- iOS - Analyze 静态分析
- C++_构造函数与析构函数
- BZOJ1305 [CQOI2009]dance跳舞 【网络流】
- 重新 java 对象的 equals 和 hashCode 方法的建议和示例代码
- labview密码忘记怎么办,如何破解labview密码,vi密码md5码破解重置
热门文章
- (JavaScript基础向)sort()方法里的排序函数的理解
- MES制造系统
- 00090_字节输入流InputStream
- 算法中的优化问题(optimization problem)
- Validation failed for query for method public abstract boxfish.bean.Student boxfish.service.StudentServiceBean.find(java.lang.String)!
- python3 求斐波那契数列(Fibonacci sequence)
- change_names
- PAL相机
- Surging Demo 项目之一
- Java中关于static语句块的理解