erlang的terminate解析

gen_server gen_server 概述 阅读详情

一个erlang application启动之后,通常需要在一定时间后停止,一般会采用application:stop/1来停止一个application。如果我们希望在stop application的同时还能做些操作,例如持久化,数据清理之类的事情,就要利用terminate了。废话不多说,直接上代码:

start() ->
    {ok, _} = supervisor:start_child(test_sup, []).
start_link() ->
    gen_server:start_link(?MODULE, [], []).
init([]) ->
    {ok, #state{}}.<pre name="code" class="java">terminate(Reason, _State) ->
    io:format("i'm terminate:~p~n", [Reason]),
    timer:sleep(10000),
    io:format("~s", ["end"]),
    ok.
handle_info({'EXIT', _, Reason}, State) ->
    io:format("exit:~p~n", [Reason]),
    {stop, normal, State};


上面代码是一个gen_server进程,test_sup是一个one_for_one supvisor,重启策略permanent,shutdown策略infinity,调用application:stop/1来停止,发现terminate并没有执行到。源码是最好的工具,上源码:

%%
%% Terminate this server.
%%
-spec terminate(term(), state()) -> 'ok'.

terminate(_Reason, #state{children=[Child]} = State) when ?is_simple(State) ->
    terminate_dynamic_children(Child, dynamics_db(Child#child.restart_type,
                                                  State#state.dynamics),
                               State#state.name);
terminate(_Reason, State) ->
    terminate_children(State#state.children, State#state.name).
上面是supervisor的terminate方法,可以看到对于simple_one_for_one这种类型,supervisor是特殊处理的,这里,我们关注terminate_children/2这个方法。

terminate_children([Child = #child{restart_type=temporary} | Children], SupName, Res) ->
    do_terminate(Child, SupName),
    terminate_children(Children, SupName, Res);
terminate_children([Child | Children], SupName, Res) ->
    NChild = do_terminate(Child, SupName),
    terminate_children(Children, SupName, [NChild | Res]);
terminate_children([], _SupName, Res) ->
    Res.

do_terminate(Child, SupName) when is_pid(Child#child.pid) ->
    case shutdown(Child#child.pid, Child#child.shutdown) of
        ok ->
            ok;
        {error, normal} when Child#child.restart_type =/= permanent ->
            ok;
        {error, OtherReason} ->
            report_error(shutdown_error, OtherReason, Child, SupName)
    end,
    Child#child{pid = undefined};
do_terminate(Child, _SupName) ->
    Child#child{pid = undefined}.
terminate_children/2这个方法是一个尾递归,作用就是对每一个child都执行do_terminate/2,do_terminate/2很简单,就是直接shutdowns
shutdown(Pid, brutal_kill) ->
    case monitor_child(Pid) of
	ok ->
	    exit(Pid, kill),
	    receive
		{'DOWN', _MRef, process, Pid, killed} ->
		    ok;
		{'DOWN', _MRef, process, Pid, OtherReason} ->
		    {error, OtherReason}
	    end;
	{error, Reason} ->      
	    {error, Reason}
    end;
shutdown(Pid, Time) ->
    case monitor_child(Pid) of
	ok ->
	    exit(Pid, shutdown), %% Try to shutdown gracefully
	    receive 
		{'DOWN', _MRef, process, Pid, shutdown} ->
		    ok;
		{'DOWN', _MRef, process, Pid, OtherReason} ->
		    {error, OtherReason}
	    after Time ->
		    exit(Pid, kill),  %% Force termination.
		    receive
			{'DOWN', _MRef, process, Pid, OtherReason} ->
			    {error, OtherReason}
		    end
	    end;
	{error, Reason} ->      
	    {error, Reason}
    end.
shutdown/2中对brant_kill这种shutdown机制做了特殊处理,具体就是monitor_child/2之后直接kill进程,要知道,exit(PID, kill)这个方法执行之后,对应PID不管是否trap_exit都无法抓取退出消息的,也就是不会执行terminate,所以如果退出需要做处理,请不要设置brant_kill。如果不是brant_kill,在monitor_child/2之后,调用exit(PID, shutdown),用这种方法停止PID,所以在这种情况下想要执行terminate必须:PID是一个trap_exit为true的进程。
把最开始那段测试代码加上trap_exit,再次stop,查看输出发现有执行到terminate,但是没有执行到handle_info那里,这是为什么呢?这个和gen_server有关。

loop(Parent, Name, State, Mod, hibernate, Debug) ->
    proc_lib:hibernate(?MODULE,wake_hib,[Parent, Name, State, Mod, Debug]);
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).

wake_hib(Parent, Name, State, Mod, Debug) ->
    Msg = receive
	      Input ->
		  Input
	  end,
    decode_msg(Msg, Parent, Name, State, Mod, hibernate, Debug, true).

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, fun print_event/3,
				      Name, {in, Msg}),
	    handle_msg(Msg, Parent, Name, State, Mod, Debug1)
    end.
gen_server进程其实是在不断的执行loop/6,当收到消息时,调用decode_msg/7来解析,可以看到,decode_msg/7中,对{'EXIT', Parent, Reason}这种消息做了特殊处理,具体就是直接调用terminate/6。所以,对于gen_server来说,父进程发来的EXIT消息,是不会用handle_info来处理的,而是直接terminate。这就是为什么测试代码在stop的时候没有执行到handle_info的原因。

源码和文档果真是最好的工具。

用Python+OpenCV给斗地主做个‘外挂’:手把手教你写个桌面记牌器(附源码) 本文详细介绍了如何使用Python和OpenCV开发一个智能斗地主记牌器,包括环境搭建、图像采集与预处理、扑克牌识别技术及PyQt5界面设计。通过实战案例,帮助开发者掌握图像处理与界面开发的结合应用,提升游戏辅助工具的编写能力。 阅读详情

相关推荐

人脸关键点定义汇总

前几天看一份代码临时需要找49个人脸关键点位置定义的图片发现怎么百度都搜不到,最后幸好谷歌可以使用了就用谷歌搜到了。所以在这里汇总一下我所知道的人脸关键点的定义和相关的一点东西,以备不时之需。 68个关键点 最常用的工具是Dlib,网址:http://dlib.net/ dlib的68个特征点检测算法是ERT算法【1】 使用dlib检测68个特征点的python示例见:http://dlib.n...

程序媛 7642

Erlang OTP之terminate 深入分析

转载:庆亮的博客-webgame架构 一、terminate简述及问题产生   terminate是gen_server的一个回调函数,如果一个gen_server进程设置了trap_exit为true(process_flag(trap_exit, true)),则在该进程结束时会自动调用terminate。利用这个功能,我们可以在进程退出时进行一些善后工作,例如持久化数据、清理等等。

剪裁人生 的专栏 1968

三. zemax光学设计流程+案例

文章目录zemax 基本操作:1. 建立光学基本模型2. 像质评价3. 优化(重点)4. 公差分析简单镜头设计 zemax 基本操作: 1. 建立光学基本模型 2. 像质评价 3. 优化(重点) 对系统设定的约束条件或目标值 统称为操作数。 操作数: 光学特性参数(焦距EFFL,近轴放大率PMAG,入瞳位置EMPP) 像差参数(球差SPHA,彗差COMA,像散ASTI) 边界条件(中心厚度值CTVA,边缘厚度值ETAV) 优化的主要步骤: 设置评价函数和优化操作数 一般小像差系统采用波像差 构建

Taiiiii的博客 8054

RabbitMQ不定时宕机,求解

RabbitMQ宕机

weixin_44235608的博客 3784

腾讯微搭低代码开发实战电子书:医疗挂号小程序

本书通过一个完整的“医疗挂号小程序”项目,深度讲解腾讯微搭(WeDa)低代码平台在复杂业务场景下的实战应用。从登录体系搭建、用户注册,到就诊人管理、科室排班与预约下单,全程遵循“配置+逻辑+实战”的思路,带领读者从零实现具备商业级可用性的医疗挂号小程序,掌握低代码开发的核心技巧与业务落地能力。

低代码布道师的博客 952

数据科学助力大数据领域的航空安全分析

随着航空业的快速发展,航班数量不断增加,航空安全问题日益受到关注。大数据时代的到来,使得航空领域积累了大量的数据,包括飞行数据、维护数据、气象数据等。本文章的目的在于探讨如何运用数据科学的方法和技术,对这些大数据进行分析,以提高航空安全水平。范围涵盖了从数据收集、预处理到数据分析、模型构建和应用的整个流程。本文将按照以下结构进行组织:首先介绍数据科学和航空安全分析的核心概念以及它们之间的联系;接着阐述核心算法原理和具体操作步骤,并使用Python源代码进行详细说明;

软件工程实践的博客 1292

erlang安装问题(State machine user_ dru terminating)

主要原因是安装的erlang版本太高导致,建议选择对应rabbitmq并且是中版本的。新版本会有各种各样适配问题。如果现在26 建议选用25中间 对应rabbitmq低一个版本,稳定性更好。输入erl 出现错误 State machine user_ dru terminating。

不要和代码过不去 1825

万字长文:YOLOv5+RK3588 NPU多线程加速全攻略——从理论到部署的终极优化

RK3588 NPU多线程加速优化教程摘要 本教程深入讲解了如何利用线程池技术优化RK3588 NPU上的YOLO目标检测模型推理性能。RK3588内置3个NPU核心,理论算力达6TOPS,为多线程优化提供了硬件基础。教程详细解析了线程池的核心组件(任务队列、工作线程、同步机制)和实现架构,包括类设计、初始化流程、工作线程逻辑(任务获取、NPU推理、结果存储三个阶段)以及任务提交/获取机制。通过预分配模型实例、线程绑定、流量控制等优化手段,实现了从单线程28FPS到多线程120FPS的显著性能提升,为边缘A

LXY_LOVE36的博客 1101

4.Erlang 错误处理

一,运行错误 1.function_clause:无模式匹配 2.case_clause:case误模式匹配 3.if_clause:if没有模式匹配 4.badmatch:变量已经被绑定 5.badarg:参数错误 6.undef:没有函数 7.badarith:算术运算错误 二,处理错误 1> try (X=3) of Val->{normal,...

浏览器开发教学 895

Error: Flash Download failed - Target DLL has been cancelled

由于换了新电脑,keil重装了下,然而之前的MCU的支持包没有安装,以及一些其他的问题,导致可以编译但是不能将程序烧录到单片机中。现整理一下解决思路: 1、将支持包下载并添加: 找到你需要用的MCU的具体型号: 例如: 点击网址,下载安装包,或者在csdn等其他网址下载安装包,将下载好的pack包放到keil5的安装目录下的.Download中: 点击file中的import,将路径选择到.........

hanhan的博客 5万+

C#实战YOLO26物体检测:从ONNX模型转换到工业级部署全复盘

本文介绍了在C#上位机中集成YOLO26模型实现工业产线零件检测的实战方案。针对工业场景对实时性(单帧推理≤100ms)、轻量化和易部署的需求,选择YOLO26模型相比YOLOv8在推理速度提升30%且模型体积更小。文章详细拆解了从模型转换(PyTorch转ONNX)、C#推理引擎封装到部署优化的全流程,重点解决了ONNX兼容性、坐标偏移、GPU降级等工业落地中的典型问题。通过解耦设计、性能优化和异常处理机制,最终在工控机(i5-8500+GTX1650)上实现60ms的单帧推理速度,为工业检测项目提供了可

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1325

erlang mysql:start_link_Erlang OTP之terminate 深入分析

gen_server进程设置了trap_exit为true(process_flag(trap_exit,true)),则在该进程结束时会自动调用terminate。利用这个功能,我们可以在进程退出时进行一些善后工作,例如持久化数据、清理等等。但实际上terminate不一定有时间完成所有的任务,在此之前可能已经被系统强制结束了(如果使用init:stop形式结束beam)。二、测试termina...

weixin_33404102的博客 327

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

erlang gen_server terminate

原文地址 总结一下: 使用exit(Pid,Reason)时: gen_server设置了trap_exit为false时,不会进行信号的转换, 1.Reason为normal,gen_server不退出,terminate不执行; 2.Reason为test、shutdown、kill、other时。gen_server退出,terminate不执行 gen_server设置了trap_exit...

牛逼! 454

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Erlang的gen_server的terminate使用的几点总结

(1)terminate只有在捕获到信号的情况下,即收到{'Exit‘,From,Reason}消息时,里面被执行,因此必须设置process_flag(trap_exit,true);      能捕获信号的情况:     a、gen_server主动退出:正常退出执行了stop方法和异常退出(代码本身的问题所致,如无匹配,逻辑语法错误等或是执行了exit(pid,test))     b

zcc_0015的专栏 5497

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

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 termina...

weixin_33912638的博客 163

gen_server, trap_exit和terminate/2

转载请注明:来自http://blog.youkuaiyun.com/skyman_2001 1. 若gen_server进程自己终止(比如返回stop或在回调里触发exit,这里的exit可以是正常退出或异常退出,比如代码运行异常时会导致异常退出),则terminate/2总是被调用(即不管有没有设置捕捉退出消息);否则  2. 若gen_server进程没设置捕捉退出消息,则不会有terminate/

Skyman的部落格 2431

Erlang OTP 内部细节之gen_server

如果gen_server进程需要在死亡的时候调用terminate函数,则需要调用process_flag(trap_exit, true)设置为系统进程。但是什么时候需要在handle_info中处理{'EXIT', FROM, REASON}消息呢?我的观点是,如果我们在继承了gen_server的进程中关联了其他进程(不包括父进程,如supervisor进程),那么就需要在handle_in...

weixin_34205076的博客 174

深入理解gen_smtp架构:OTP风格回调模块设计与扩展技巧

gen_smtp是一个功能强大的可扩展Erlang SMTP客户端和服务器库,采用OTP(开放电信平台)设计原则构建,为开发者提供了灵活的回调机制和模块化架构。本文将深入探讨gen_smtp的核心架构设计,重点解析其OTP风格的回调模块实现,并分享实用的扩展技巧,帮助开发者更好地理解和使用这个优秀的开源库。 ## OTP架构基础:回调模块设计理念 OTP是Erlang生态系统的基石,其设计思想

gitblog_00376的博客 406

Supervisor with gen_server

转载请注明,来自:http://blog.youkuaiyun.com/skyman_2001 当gen_server进程加到监督树里,要想让它的supervisor终止时回调该gen_server进程的terminate()(可以在terminate()函数里做些清理工作),可以: 1. 该gen_server进程设置了捕捉退出信号:erlang:process_flag(trap_exit, tr...

seloba 215

erlang sys学习

http://www.hoterran.info/erlang-otp-sys-sourcecode -module(ch4). -export([start_link/0]). -export([alloc/0, free/1]). -export([init/1]). -export([system_continue/3, system_terminate/4,          

足下千里 616

erlang OTP gen_server 图解分析

http://www.hoterran.info/otp-gen_server-sourcecode 在阅读erlang的otp源码gen_server.erl的时候,一直想写点什么,用一种最好的方式表达出来,最终却总是没法表达清楚,困惑之余看到这篇文章,作者用图解的方式,非常清晰明了的表达了我一直想表达的东西,下面是原文链接: http://www.hoterran.info/otp-gen...

weixin_30587927的博客 105

Erlang gen_server深度解析:构建高并发系统的7个核心模式与实战技巧

Erlang/OTP作为构建高并发、分布式系统的成熟平台,其核心组件gen_server为开发者提供了构建可靠服务器进程的标准框架。本文将深入探讨gen_server的设计原理、核心模式以及在实际项目中的应用技巧,帮助中级开发者掌握这一构建企业级应用的关键技术。 ## 为什么gen_server是Erlang并发模型的基石? 在分布式系统中,服务器进程需要处理复杂的并发请求、状态管理和错误恢复

gitblog_00085的博客 194

erlang trap_exit标记

本篇博文分析设置了 trap_exit 标记为 true 的gen_server 进程会如何处理收到的退出信号。 设置了 trap_exit 为 true 的进程,在收到 非kill 的退出信号时候,会把该信号转换为普通的消息,而不会退出;通过gen_server:handle_msg/5 和 gen_server:handle_msg/6 函数可知,若进程自身发生错误的时候,即使...

diewuyun3156的博客 182

dotfiles 的 Pi Calm 扩展源码完整剖析:动画小船渲染、零侵入过滤与优雅降级实现原理

dotfiles 是一个用 Nix 管理的个人开发环境仓库,其中藏着一个精致的 Pi 本地扩展——**Pi Calm**。它在 AI 编码代理 Pi 工作时,用一行动画小船替代默认的状态行,并"无痕"隐藏工具调用的外壳与折叠的思考内容,同时绝不改动任何会话数据。本文带你逐行看懂它三大核心机制的实现原理:动画小船渲染、零侵入过滤、优雅降级。 ## 先认识 Pi Calm:一个"只改显示、不动数据"

gitblog_00526的博客 860
上一篇: 记一次erlang分布式系统的bug修复过程
下一篇: erlang另类方法调用
pyf725324
博客等级 码龄17年 6粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值