源码位置位于安装目录的lib/stdlib/src下。

之前在使用gen_server时,由于之前自己实现过一个gen_server,因此对它内部的机制也能知道个七七八八,最近在用erlang的fsm模块,突然想读一读它得源码,这才突然发现erlang的源码内部还是做了很复杂的工作,尤其是有个“阴魂不散”的模块proc_lib。

无论是gen_server也好,gen_fsm也好,实际上在start的时候,都是调用的底层gen模块的start/start_link函数,由start函数调用do_spawn函数,在这里,就和我之前想象的不一样了,在我之前的印象里,这里应该直接用spawn,回调用户编写的init函数,但是,实际上不是这样的,我们看下源码:

Time = timeout(Options),    %这个函数获取timeout的时间,默认为infinity

然后开始调用proc_lib的start函数:

proc_lib:start(?MODULE, init_it, [GenMod, self(), self(), Name, Mod, Args, Options], Time, spawn_opts(Options))

其中,spawn_opts实在获取spawn的参数。

我们跟进到proc_lib的内部,看看start函数做了些什么。

在start函数的第一行返回了一个Pid,那么我们已经能够猜到spawn_opt内部应该是spawn新的进程了。在spawn_opt函数中,首先获取了Parent(proc_lib进程的名字)以及Ancestors,然后调用erlang模块的spawn_opt函数。

这个函数会调用当前进程的init_p方法,现在要注意,此时spawn_opt派生了新的进程,那么原来的parent进程会直接返回一个Pid,这个Pid就被我们之前看到的proc_lib:start的地方接收了,并且继续向下执行了sync_wait(Pid, Timeout)函数,在sync_wait函数的内部在等待接收消息,如果超过timout的时间没有接收到,就认为失败了,那么我们可以推测,派生出来的进程一定是去执行用户的init的函数去了,并且在执行完后会发给parent进程一个消息。

我们看看我们的猜测对不对,继续跟进到init_p函数内部,我们可以看到函数内部开始搜刮者用户传递进来的Fun的所有信息,并放入进程字典中(真的不喜欢进程字典),然后开始执行用户的Fun函数,然后该进程结束。

是的,你没有看错,你没有发现任何地方向parent进程发送了ack信号,这不科学,因为这意味着parent会因为超时而报错,如果你这么想,你一定是把执行的Fun函数当成了你的init,我们网上看就能发现实际上是gen模块的init_it函数,这里还有个不太好的地方就是init_it调用了函数init_it2…这命名规则着实让人蛋疼……

init_it2回调了用户传入的init_it函数,这个函数是由对应的行为模式编写的init_it函数,比如举个简单的例子,在gen_server的源码中,init_it就调用了用户传入的init函数,并且在执行后,调用init_ack,init_ack函数向parent进程发送了一个成功的消息,之后,gen_server进入loop函数开始接收消息,也就是说,用户的gen_server:start()函数执行完毕。也印证了我们之前的猜想是正确的。

其实,这里我有个疑问,不知道作者为什么不把proc_lib:init_ack函数放在proc_lib的init_p函数的最后执行呢?

我们只是简单的分析了proc_lib的spawn与直接spawn有哪些不同,那么对于我们来说,proc_lib还有哪些直接挖掘的呢?为什么要用proc_lib去包装spawn呢?

翻翻proc_lib的代码,在上文中,我们也可以看出,在spawn之前,保存了不少信息,比如parent进程的信息和相关的函数信息,这些在用procss_info查看时,都可以直观的看到。同时,模块向外暴露的initial_call函数,translate_initial_call函数以及raw_initial_call函数也可以查看。至于函数内部的实现就不多讨论了,比较简单。

最后,我们会发现还有个有趣的函数crash_report,我们分析源码能够看出,对于proc_lib派生的进程来说,退出信号是normal以及shutdown都会被认为是正常退出。其他的出错信息会被error_logger模块捕捉。

最后的最后,还有一个非常有意思的函数,就是hibernate函数,这个函数看起来就让java程序员很亲切,官方手册上,对erlang模块的hibernate函数的解释大约是把当前正在运行的线程处于一个wait的状态,此时,进程会抛弃掉自己的调用栈,并且进行gc,然后wait,直到信箱中接受到了新的消息。很明显的,这种情况应该是当前进程在一段时间内预计不会收到消息,为了节省内存而触发的,在高并发的场景下对内存的节省会起到一定的作用。同时,文档上还说,当进程收到新的消息被唤醒,并且将函数的控制权交给作为参数被传入的Fun。

问题出现了,既然调用栈被抛弃了,那么Fun执行完后何去何从?显然进程这不就直接结束了?当然不是,proc_lib对hibernate做了个封装,当被唤醒时会回调用户传入的函数,比如gen_server,那么wake_hib最终会被回调,我们可以看到,在gen_server中,wake_hib在处理完刚刚接受到得消息后,重新回到了handle_msg的函数中继续等待接收消息。

对于proc_lib,值得说说的也就这么多,代码不是很长,大约700多行,这个模块理解了,本身gen模块东西也不多,那么所有的otp模式也就比较简单了。

恩,就是这样。

转载于:https://www.cnblogs.com/chunming-d/p/3766054.html

[erlang]proc_lib源码浅析相关推荐

  1. hashmap允许null键和值吗_hashMap底层源码浅析

    来源:https://blog.csdn.net/qq_35824590/article/details/111769203 hashmap是我们经常使用的一个工具类.那么知道它的一些原理和特性吗? ...

  2. Android Loader机制全面详解及源码浅析

    原文出处:csdn@工匠若水,http://blog.csdn.net/yanbober/article/details/48861457 一.概述 在Android中任何耗时的操作都不能放在UI主线 ...

  3. 内核启动流程分析(四)源码浅析

    目录 kernel(四)源码浅析 建立工程 启动简析 head.s 入口点 查询处理器 查询机器ID 启动MMU 其他操作 start_kernel 处理命令行 分区 kernel(四)源码浅析 建立 ...

  4. harbor登录验证_Harbor 源码浅析

    Harbor 源码浅析​www.qikqiak.com Harbor 是一个CNCF基金会托管的开源的可信的云原生docker registry项目,可以用于存储.签名.扫描镜像内容,Harbor 通 ...

  5. fetch first mysql_MySQL多版本并发控制机制(MVCC)源码浅析

    MySQL多版本并发控制机制(MVCC)-源码浅析 前言 作为一个数据库爱好者,自己动手写过简单的SQL解析器以及存储引擎,但感觉还是不够过瘾.<>诚然讲的非常透彻,但只能提纲挈领,不能让 ...

  6. 【flink】Flink 1.12.2 源码浅析 : Task数据输入

    1.概述 转载:Flink 1.12.2 源码浅析 : Task数据输入 在 Task 中,InputGate 是对输入的封装,InputGate 是和 JobGraph 中 JobEdge 一一对应 ...

  7. 【flink】Flink 1.12.2 源码浅析 :Task数据输出

    1.概述 转载:Flink 1.12.2 源码浅析 :Task数据输出 Stream的计算模型采用的是PUSH模式, 上游主动向下游推送数据, 上下游之间采用生产者-消费者模式, 下游收到数据触发计算 ...

  8. 【flink】Flink 1.12.2 源码浅析 : StreamTask 浅析

    1.概述 转载:Flink 1.12.2 源码浅析 : StreamTask 浅析 在Task类的doRun方法中, 首先会构建一个运行环境变量RuntimeEnvironment . 然后会调用lo ...

  9. 【flink】Flink 1.12.2 源码浅析 : Task 浅析

    1.概述 转载:Flink 1.12.2 源码浅析 : Task 浅析 Task 表示TaskManager上并行 subtask 的一次执行. Task封装了一个Flink operator(也可能 ...

最新文章

  1. JQuery Autocomplete实战
  2. IPCC气候变暖最新报告:不要眼见,要“远见”
  3. [ARM异常]-ARMV8-aarch64异常和中断处理概念详细介绍
  4. 拦截器 java_在Java后端如何添加拦截器
  5. js laypage mysql_layui中的分页laypage
  6. jdk 细粒度锁_使用JDK 8轻松进行细粒度排序
  7. 微信你scope 参数错误 php,微信开发: scope参数错误或没有scope权限解决方法
  8. Gensee移动SDK之(二)协议
  9. input中checked复选框进行单选
  10. autotools工具介绍
  11. c++不好可以学qt吗_学美容好不好,学美容有前途吗?
  12. IOS-播放器开发(1)-视频基本原理
  13. fastboot命令大全
  14. 代码评审系统 ReviewBoard 和 Gerrit
  15. 混沌序列加密matlab,基于复合混沌序列的图像加密算法
  16. linux给文件夹腹权限,文件的权限_腹有诗书气自华的技术博客_51CTO博客
  17. 2022前端秋招面试题总结 阿里 腾讯 字节 百度 网易 京东 小红书 快手面试记录
  18. 在 Mac/win7 下上使用 Vagrant 打造本地开发环境
  19. kingcms php,KingCMS php版网站标签模版制作教程(二)
  20. 编译单个java文件

热门文章

  1. 图像拼接 SIFT资料合集
  2. 哈尔特征(Haar-like features)
  3. Python3 类和继承和组合
  4. Message Loop 原理及应用
  5. ajax就收data的参数
  6. Forefront Client Security部署及配置
  7. Twitter Snowflake算法详解
  8. The RSpec Book笔记《一》初步认识TDD,BDD,RSpec,Cucumber
  9. kettle 数据转换
  10. [转] 新入社員の自己紹介