Erlang generic standard behaviours -- gen

在分析 gen_server (或者是gen_fsm )之前,首先应该弄明白,gen 这个module .

1 -module(gen).
2 -compile({inline,[get_node/1]}).
3
4 %%%-----------------------------------------------------------------
5 %%% This module implements the really generic stuff of the generic
6 %%% standard behaviours (e.g. gen_server, gen_fsm).
7 %%%
8 %%% The standard behaviour should export init_it/6.
9 %%%-----------------------------------------------------------------

也就是说,gen 这个模块 gen_server ,gen_fsm 的基础.

PS. 无特殊说明,以下提到的gen_server 都指代gen_server 和 gen_fsm .

export func

1 -export([start/5, start/6, debug_options/1,
2           call/3, call/4, reply/2]).

gen 模块导出了以上这些函数,其中:

start/N 是用于spawn gen_server 进程. 基本的流程是使用proc_lib:spawn(_link) 创建新的process, 并以init_it 作为初始化函数, 继而回调 gen_server 模块中的init_it函数, 完成gen_server 模块的init .

call/N 是用于gen_server call func 的实现,也就是 gen_server:call 的实际调用.

reply/2 的实现相对“简单”,即调用bif erlang:‘!‘/2 发送消息. 但是这个函数的作用很大, 之后会一一提到.

start/N

start/5 用于创建无名gen_server , start/6 用于创建指定name 的gen_server .

 1     start(GenMod, LinkP, Name, Mod, Args, Options)
 2         GenMod  :: gen_server | gen_fsm
 3         LinkP   :: nolink     | link
 4         Name    :: {local, atom()} | {global, term()} | {via, atom(), term()} %% 就是指定的name
 5         Mod     :: atom() %% 就是使用了gen_server behaviour 的模块名
 6         Args    :: term() %% Mod 模块 init func 的初始参数
 7         Options :: [{timeout, Timeout} | {debug, [Flag]} | {spawn_opt, OptionList}] %% 这个参数是用来指定创建进程的参数
 8
 9
10         Flag    :: trace | log | {logfile, File} | statistics | debug
1     start(GenMod, LinkP, Mod, Args, Options)
2         %% 相比start/6, 没有了执行name 的参数

start/6 会先确认给定的name 是否已经被使用, 如果被使用, 会返回

1 {error, {already_started, Pid}} %% Pid 是名字为name 的进程

反之, 继续执行do_spawn , do_spawn 会调用proc_lib:spawn(_link) 函数创建进程, 并以 init_it 为初始化函数. (先挖个坑, ** proc_lib:spawn VS erlang:spawn ** 后面填)

注意, 此时已经有新的进程被创建了, 而 init_it 函数,已经是在由新的进程执行.

1     init_it(GenMod, Starter, Parent, Mod, Args, Options)
2         Starter :: pid() %% 即调用proc_lib:spawn 的进程
3         Parent  :: pid() | atom() %% Parent 只有在以link方式 start的时候才有意义 (此坑后填)
4     init_it(GenMod, Starter, Parent, Name, Mod, Args, Options)
5         %% Name 即指定的name, 首先会以Name 为参数调用 name_register/1
6
7     init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options) ->
8         GenMod:init_it(Starter, Parent, Name, Mod, Args, Options).
9     %% 回调 gen_server/gen_fsm 模块的init_it 函数

call/N

call/3 使用default_timeout 作为第四个参数调用 call/4 .

call/4 首先会进程一系列的参数校验, 然后调用do_call/4

 1     do_call(Process, Label, Request, Timeout) ->
 2         %% 首先调用 bif monitor Process
 3         try erlang:monitor(process, Process) of
 4         Mref ->
 5             %% 然后给 Process 发送消息
 6             catch erlang:send(Process, {Label, {self(), Mref}, Request},
 7               [noconnect]),
 8             %% 并等待 Process 的返回结果, 就是在 handle_call 中的Reply 或者是 gen:reply 的 结果
 9             receive
10             {Mref, Reply} ->
11                 %% 关于 erlang:monitor/erlang:demonitor 的文档很详细
12                 erlang:demonitor(Mref, [flush]),
13                 {ok, Reply};
14             {‘DOWN‘, Mref, _, _, noconnection} ->
15                 Node = get_node(Process),
16                 exit({nodedown, Node});
17             {‘DOWN‘, Mref, _, _, Reason} ->
18                 exit(Reason)
19             after Timeout ->
20                 erlang:demonitor(Mref, [flush]),
21                 exit(timeout)
22             end
23         catch
24         %% bif monitor Process 失败, 就 monitor Process 所在的 Node
25         error:_ ->
26             Node = get_node(Process),
27             monitor_node(Node, true),
28             receive
29             {nodedown, Node} ->
30                 monitor_node(Node, false),
31                 exit({nodedown, Node})
32             after 0 ->
33                 Tag = make_ref(),
34                 %% bif erlang:‘!‘/2 发送消息
35                 Process ! {Label, {self(), Tag}, Request},
36                 %% 等待响应
37                 wait_resp(Node, Tag, Timeout)
38             end
39         end.

call/3 以及 call/4 主要就做了这些事情.

reply/2

此函数实现在erl 代码层面很简单, 但对gen_server 进程来说,有独特的作用,后续会进行分析.

填坑

proc_lib:spawn 和 erlang:spawn 的区别:

翻下代码,就能看到, so easy

相比较 erlang:spawn, proc_lib:spawn 在被创建的进程中,添加了一些信息:

‘$ancestors‘,  ‘$initial_call‘.

在某些场景下,这些信息对于定位进程的归属有很大的作用.比如说:定位僵死进程的归属,定位崩溃进程的归属等.

时间: 2024-10-23 00:32:31

Erlang generic standard behaviours -- gen的相关文章

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 generic standard behaviours -- gen_server terminate

gen_server 主体 module 已经分析完了(http://www.cnblogs.com/--00/p/4271982.html),接着,分析下gen_server 中的terminate .首先分析一个问题, 这个问题是之前在weibo 上和别人讨论过的一个问题: Why will a rpc:call started gen_server process terminate with normal reason? 注:被call 的gen_server 进程 trap_exit

Erlang generic standard behaviours -- gen_server module

在分析完gen module 之后,就可以开始进入gen_server 的主体module 了.gen_server 的主体 module 暂不涵括terminate, hibernate, debug trace 相关的内容,这些会单独拉出来分析. gen_server 主要包括start 初始化部分, MAIN loop. 其中MAIN loop 为gen_server的主体结构, 其中,处理Label 为'$gen_call' (也就是handle_call)的消息使用handle_msg

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

接触Erlang有段时间了,之前一直懒得总结,发现很多东西都是散落各处,总想拾起,可又感觉像是流沙. 就从现在开始吧,慢慢总结起来,捡起来. 先计划写一些系列性的,比如说generic standard behaviours.beach的一些小东西.常用的一些开源工具.生产环境下虚拟机参数的调整.看到的一些论文.重复造的一些轮子等,也希望能更进一步,看一些erts 的内容,尝试学习.分析. 如果有幸能被一些博友看到,也希望能多交流. :)

jQv1.5源代码重读

/*! * jQuery JavaScript Library v1.5 * http://jquery.com/ * * Copyright 2011, John Resig * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * Includes Sizzle.js * http://sizzlejs.com/ * Copyright 2011, The Dojo Fou

jQ1.5源码注释以及解读RE

jQ作为javascript的库( ▼-▼ ), 尽善尽美, 代码优美,  值得学习.  这一周平常上班没啥事也看jQ1.5的代码, 今天周六差不多看完了(Sizzle部分还没看), 重新看了一下, 又有很多新东西; 相对与1.4版本的ajax部分, 整个进行了重写, 实在是坑爹,  现在还有很多没弄懂,  ajax可以非常简单地: var xhr = new XMLHttpReques || new window.ActiveXObject("Microsoft.XMLHTTP");

Java性能提示(全)

http://www.onjava.com/pub/a/onjava/2001/05/30/optimization.htmlComparing the performance of LinkedLists and ArrayLists (and Vectors) (Page last updated May 2001, Added 2001-06-18, Author Jack Shirazi, Publisher OnJava). Tips: ArrayList is faster than

C++ generic tools -- from C++ Standard Library

今晚学了一下C++标准程序库, 来简单回顾和总结一下. 1.pair 结构体 // defined in <utility> , in the std namespace namespace std{ template <class T1, class T2> struct pair{ // type names for the values typedef T1 first_type; typedef T2 second_type; // member T1 first; T2