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的执行循环。

时间: 2024-08-29 15:25:28

gen_server的enter_loop分析的相关文章

Gen_server行为分析与实践

1.简介 Gen_server实现了通用服务器client_server原理,几个不同的客户端去分享服务端管理的资源(如图),gen_server提供标准的接口函数和包含追踪功能以及错误报告来实现通用的服务器,同时可以作为OTP监控树的一部分. Gen_server函数与回调函数之间的关系: 1 gen_server module Callback module 2 ----------------- --------------- 3 gen_server:start_link ----->

gen_server和gen_server2 源码分析

据某erlang大牛说,erlang project里90%的module都是gen_server RabbitMQ重新实现了gen_server -> gen_server2. 很多Module都是用了这个behavior. 我们首先来看下OTP里gen_server 的实现: gen_server的启动入口是gen_server:start_link,一个以gen_server为behavior的Module,例如frontend call gen_server:start_link( no

Erlang generic standard behaviours -- gen_server system msg

这是Erlang generic standard behaviors gen_server 分析的系列的最后一篇,主要分析gen_server module 辅助性的功能函数. 在gen_server 的MAIN loop 流程中,除了处理Parent 的'EXIT' 消息, user module 常规消息之外, 还处理了一类 system 消息. 这一类system 消息的来源是一个sys 的module,在Erlang OTP体系中,sys module 主要有两大类的作用,一个是热更,

erlang监控进程在启动进程退出后异常退出原因分析

一.问题引出 erlang监控进程在启动时设置了trap_exit为true,即会捕获到退出信号,会将退出信号转换为{'EXIT',Pid,Reason}存入自己的邮箱中,因此与监控进程link关系的进程退出后,监控进程能够很坦然的截获退出信号,自身不退出.启动erlang监控进程的进程,会和监控进程建立link关系,然而当启动进程退出时,监控进程没有象正常的情况,发生了异常退出,为什么设置了trap_exit为true,还会退出呢? 二.原因分析 查看supervisor的源码,supervi

Erlang generic standard behaviours -- gen_server noblock call

在Erlang 系统中,经常需要gen_server 进程来处理共享性的数据,也就是总希望一个gen_server 进程来为多个普通进程提供某种通用性的服务,这也是gen_server 设计的初衷.但是,由于公平调度的原因,在Erlang体系中,每个process 能获得的资源都是同等的:同等的CPU时间片(还有默认情况下同等的初始化内存). 也就是gen_server 进程只能获得1/(N+1)的CPU时间片,为N个进程提供通用性的服务,而无法违背公平调度的原则使gen_server 进程获得

Erlang:RabbitMQ源码分析 3. supervisor和supervisor2深入分析

supervisor也是Erlang/OTP里一个常用的behavior,用于构建supervisor tree实现进程监控,故障恢复. 而RabbitMQ实现了一个supervisor2,我们从源码角度分析二者的实现和区别. 先介绍一些supervisor的基本概念,假设node_manager_sup是一个supervisor,它的init函数会定义supervisor的一些参数和它的children. 参数: 1. Restart Strategy: Strategy必须是simple_o

Erlang OTP学习(1)gen_server

在<Programming Erlang>的OTP introduction章节中,作者通过循序渐进的方式,向我们展示了gen_server设计思路,现在做下总结: 在具体看gen_server之前,我们先看一个server通用框架:  在这个server里,你几乎看不到任何和具体功能相关的东西,它只提供了一个server所具备的基本框架,那它是如何运行的呢? 当我们调用start函数时,就启动了一个服务,如果服务器接收到一条消息,那么它将会把这条消息转交给Mod:handle_call或者M

Erlang的gen_server的terminate()/2未执行

官方资料参考: Module:terminate(Reason, State) Types: Reason = normal | shutdown | {shutdown,term()} | term() State = term() This function is called by a gen_server when it is about to terminate. It should be the opposite of Module:init/1 and do any necessa

[Erlang_Question21]Erlang性能分析工具eprof fporf的应用

前段时间项目改代码突然cpu波动很大,排查了好久都没有找到原因,只能求助于性能测试工具 : <<Erlang程序设计>>----Joe Armstorng[哈哈,登月第一人也叫Armstrong] P416 cprof测试每个函数被调用了多少次,这个工具为轻量在运行系统上使用这个工具会给系统带来5%~10%的额外负载 fprof显示函数调用和被调用的埋单,并将结果输出到一个文件中,这个工具比较适合于在实验环境或模拟环境中对进行大规模的性能前一段,它会带来非常显著的系统负载. epr