Go语言标准库学习之os/signal——使用Go语言管理信号

【系统深入学习GO】signal 浅析 其中编号从 1 到 31 的信号属于标准信号 (也称不靠谱信号),而编号从 34 到 64 的信号属于实时信号 (也称靠谱信号)。而实时信号解决了标准信号的两个问题,即多个同种类的实时信号都可以记录在案,并且他们可以按照信号的发送顺序被处理。类型值的通道类型,可以简称为 signal 的接收通道。在这个数组类型的变量中,每个索引值都代表一个标准信号的编号,而对应的元素则是该信号的一个简短描述。其实就是自定义处理信号会覆盖系统默认信号的处理方法,未定义的处理信号,还是会执行系统的默认操作。 阅读详情

os/signal包实现了对输入信号的访问。这个包只有两个重要方法,这里向大家介绍一下,希望对你有帮助。

1. 信号的转发

Notify函数让signal包将输入信号转发到c。如果没有列出要传递的信号,会将所有输入信号传递到c;否则只传递列出的输入信号。

signal包不会为了向c发送信息而阻塞(就是说如果发送时c阻塞了,signal包会直接放弃):调用者应该保证c有足够的缓存空间可以跟上期望的信号频率。对使用单一信号用于通知的通道,缓存为1就足够了。

可以使用同一通道多次调用Notify:每一次都会扩展该通道接收的信号集。唯一从信号集去除信号的方法是调用Stop。可以使用同一信号和不同通道多次调用Notify:每一个通道都会独立接收到该信号的一个拷贝。

func Notify(c chan<- os.Signal, sig ...os.Signal)

Example:

package main

import (
	"fmt"
	"os"
	"os/signal"
)

func main() {
	// 初始化一个os.Signal类型的channel
	// 我们必须使用缓冲通道,否则在信号发送时如果还没有准备好接收信号,就有丢失信号的风险。
	c := make(chan os.Signal, 1)
	// notify用于监听信号
	// 参数1表示接收信号的channel
	// 参数2及后面的表示要监听的信号
	// os.Interrupt 表示中断
	// os.Kill 杀死退出进程
	signal.Notify(c, os.Interrupt, os.Kill)
	// 阻塞直到接收到信息
	s := <-c
	fmt.Println("Got signal:", s)
}

Output:

$ go run main.go   // 注意:运行代码后按`Ctrl +C`发送信号结果为:
Got signal: interrupt
2. 停止转发信号

Stop函数让signal包停止向c转发信号。它会取消之前使用c调用的所有Notify的效果。当Stop返回后,会保证c不再接收到任何信号。

func Stop(c chan<- os.Signal)

Example:

package main

import (
	"fmt"
	"os"
	"os/signal"
)

func main() {
	// 初始化一个os.Signal类型的channel
	// 我们必须使用缓冲通道,否则在信号发送时如果还没有准备好接收信号,就有丢失信号的风险。
	ch := make(chan os.Signal)
	// notify用于监听信号 默认是所有信号
	signal.Notify(ch)

	//停止向ch转发信号,ch将不再收到任何信号
	signal.Stop(ch)
	fmt.Println("signal.Stop")
	//ch将一直阻塞在这里,因为它将收不到任何信号
	//所以下面的exit输出也无法执行
	s := <-ch
	fmt.Println("Got signal:", s)
}

Output:

$ go run main.go
signal.Stop
exit status 2
3. 优雅的退出守护进程

我们先来了解一下Golang中的信号类型:

  • 在POSIX.1-1990标准中定义的信号列表
信号值值动作说明
SIGHUP1Term终端控制进程结束(终端连接断开)
SIGINT2Term用户发送INTR字符(Ctrl+C)触发
SIGQUIT3Core用户发送QUIT字符(Ctrl+/)触发
SIGILL4Core非法指令(程序错误、试图执行数据段、栈溢出等)
SIGABRT6Core调用abort函数触发
SIGFPE8Core算术运行错误(浮点运算错误、除数为零等)
SIGKILL9Term无条件结束程序(不能被捕获、阻塞或忽略)
SIGSEGV11Core无效内存引用(试图访问不属于自己的内存空间、对只读内存空间进行写操作)
SIGPIPE13Term消息管道损坏(FIFO/Socket通信时,管道未打开而进行写操作)
SIGALRM14Term时钟定时信号
SIGTERM15Term结束程序(可以被捕获、阻塞或忽略)
SIGUSR130,10,16Term用户保留
SIGUSR231,12,17Term用户保留
SIGCHLD20,17,18Ign子进程结束(由父进程接收)
SIGCONT19,18,25Cont继续执行已经停止的进程(不能被阻塞)
SIGSTOP17,19,23Stop停止进程(不能被捕获、阻塞或忽略)
SIGTSTP18,20,24Stop停止进程(可以被捕获、阻塞或忽略)
SIGTTIN21,21,26Stop后台程序从终端中读取数据时触发
SIGTTOU22,22,27Stop后台程序向终端中写数据时触发
  • 在SUSv2和POSIX.1-2001标准中的信号列表:
信号值动作说明
SIGTRAP5CoreTrap指令触发(如断点,在调试器中使用)
SIGBUS0,7,10Core非法地址(内存地址对齐错误)
SIGPOLLTermPollable event (Sys V). Synonym for SIGIO
SIGPROF27,27,29Term性能时钟信号(包含系统调用时间和进程占用CPU的时间)
SIGSYS12,31,12Core无效的系统调用(SVr4)
SIGURG16,23,21Ign有紧急数据到达Socket(4.2BSD)
SIGVTALRM26,26,28Term虚拟时钟信号(进程占用CPU的时间)(4.2BSD)
SIGXCPU24,24,30Core超过CPU时间资源限制(4.2BSD)
SIGXFSZ25,25,31Core超过文件大小资源限制(4.2BSD)

注意:需要特别说明的是,SIGKILL和SIGSTOP这两个信号既不能被应用程序捕获,也不能被操作系统阻塞或忽略。

通常我们在Linux系统中会使用kill命令来杀死进程,那其中的原理是什么呢?

  1. kill pid 方式

    kill pid的作用是向进程号为pid的进程发送SIGTERM(这是kill默认发送的信号),该信号是一个结束进程的信号且可以被应用程序捕获。若应用程序没有捕获并响应该信号的逻辑代码,则该信号的默认动作是kill掉进程。这是终止指定进程的推荐做法。

  2. kill -9 pid 方式

    kill -9 pid则是向进程号为pid的进程发送SIGKILL(该信号的编号为9),从本文上面的说明可知,SIGKILL既不能被应用程序捕获,也不能被阻塞或忽略,其动作是立即结束指定进程。通俗地说,应用程序根本无法“感知”SIGKILL信号,它在完全无准备的情况下,就被收到SIGKILL信号的操作系统给干掉了,显然,在这种“暴力”情况下,应用程序完全没有释放当前占用资源的机会。事实上,SIGKILL信号是直接发给init进程的,它收到该信号后,负责终止pid指定的进程。在某些情况下(如进程已经hang死,无响应正常信号),就可以使用kill -9来结束进程。

从上面的介绍不难看出,优雅退出可以通过捕获SIGTERM来实现。具体来讲,通常只需要两步动作:

  • 注册SIGTERM信号的处理函数并在处理函数中做一些进程退出的准备。信号处理函数的注册可以通过signal()或sigaction()来实现,其中,推荐使用后者来实现信号响应函数的设置。信号处理函数的逻辑越简单越好,通常的做法是在该函数中设置一个bool型的flag变量以表明进程收到了SIGTERM信号,准备退出。
  • 在主进程的main()中,通过类似于while(!bQuit)的逻辑来检测那个flag变量,一旦bQuit在signal handler function中被置为true,则主进程退出while()循环,接下来就是一些释放资源或dump进程当前状态或记录日志的动作,完成这些后,主进程退出。

知道了这些,我们看一下下面的例子:

package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"
)

// 优雅退出go守护进程
func main()  {
	//创建监听退出chan
	c := make(chan os.Signal)
	//监听指定信号 ctrl+c kill
	signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
	go func() {
		for s := range c {
			switch s {
			case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
				fmt.Println("退出", s)
				ExitFunc()
			default:
				fmt.Println("other", s)
			}
		}
	}()

	fmt.Println("进程启动...")
	sum := 0
	for {
		sum++
		fmt.Println("sum:", sum)
		time.Sleep(time.Second)
	}
}

func ExitFunc()  {
	fmt.Println("开始退出...")
	fmt.Println("执行清理...")
	fmt.Println("结束退出...")
	os.Exit(0)
}

测试一下:

$ go run main.go
进程启动...
sum: 1
sum: 2
sum: 3
退出 interrupt // Ctrl + C 
开始退出...
执行清理...
结束退出...
Go语言系统编程与云原生实战:构建高性能Sidecar应用 系统编程涉及与操作系统资源(如进程、内存、网络)的直接交互,传统上依赖C/C++等语言,但面临手动内存管理和复杂并发模型的挑战。Go语言通过垃圾回收(GC)和轻量级并发原语goroutine,在保持高性能的同时降低了开发复杂度,其编译生成的静态二进制文件天然契合容器化部署。在云原生架构中,可移植性、弹性伸缩和可观测性成为核心需求,Go凭借其简洁的语法、高效的并发模型和丰富的标准库,成为构建微服务、Operator和Service Mesh等云原生组件的理想选择。本文以开发一个云原生环境下的服务治理Sidec 阅读详情

相关推荐

Go语言构建企业级安全扫描工具:从并发引擎到插件化架构

在网络安全领域,自动化扫描工具是识别资产与风险的核心基础设施。其工作原理通常基于网络协议通信,通过主动探测目标端口与服务,收集指纹信息并与漏洞特征库进行匹配。这类工具的技术价值在于将重复性安全测试工作自动化,显著提升漏洞发现的效率与覆盖率。在应用场景上,它们广泛用于企业内网资产梳理、互联网暴露面监控以及合规性检查。本文聚焦于如何利用Go语言的并发模型与工程化优势,构建高并发、稳定可靠且易于扩展的安全扫描工具,其中任务调度引擎与插件化漏洞检测框架是实现企业级需求的关键组件。

chouxuyi9789的博客 475

Go标准库 os/signal 使用详解

os/signal包实现了对输入信号的访问。这个包只有两个重要方法,这里向大家介绍一下,希望对你有帮助。 1. 信号的转发 Notify函数让signal包将输入信号转发到c。如果没有列出要传递的信号,会将所有输入信号传递到c;否则只传递列出的输入信号。 signal包不会为了向c发送信息而阻塞(就是说如果发送时c阻塞了,signal包会直接放弃):调用者应该保证c有足够的缓存空间可以跟上期望的信号频率。对使用单一信号用于通知的通道,缓存为1就足够了。 可以使用同一通道多次调用Notif...

Aiky哇 5068

Go优雅关机:信号处理与连接排空

优雅关机的核心是收到信号后停止接收新请求,等在途请求处理完再退出。HTTP用Shutdown,gRPC用,都要配超时兜底。K8s场景要加preStop等待节点摘除。关机超时设多长,按最慢接口来。下一篇讲Go依赖注入Wire,看看怎么用代码生成管理复杂依赖。

白话机器学习 459

os.signal golang中的信号处理

在程序进行重启等操作时,我们需要让程序完成一些重要的任务之后,优雅地退出,Golang为我们提供了signal包,实现信号处理机制,允许Go 程序与传入的信号进行交互。

了迹奇有没 1519

基于STM32F334C8T6的四开关Buck-Boost双向DC-DC电源设计与实现(附源码、仿真与计算书)

本文详细介绍了基于STM32F334C8T6的四开关Buck-Boost双向DC-DC电源设计方案。该设计利用STM32的高分辨率定时器(HRTIM)实现精确PWM控制,支持Buck、Boost和Buck-Boost三种工作模式自动切换,具备双向能量流动能力。通过PSIM仿真和Mathcad计算书进行参数优化,实测效率达95.8%,适用于新能源系统和电池管理等场景。

www00的博客 528

基于立创EDA的8口全千兆POE交换机设计详解:RTL8370N芯片与90W大功率供电方案

本文详细解析了基于立创EDA设计的8口全千兆POE交换机方案,核心采用RTL8370N交换芯片与支持90W大功率供电的IEEE 802.3bt标准PD芯片。文章深入探讨了PSE/PD供电管理、电源架构设计、电路细节及关键散热方案,为DIY或学习POE交换机硬件设计提供了完整的开源实践指南。

weixin_29050829的博客 1万+

Golang 中的信号(Signal)机制详解

Signal 是一种操作系统级别的事件通知机制,进程可以响应特定的系统信号。这些信号用于指示进程执行特定的操作,如程序终止、挂起、恢复等。Golang 的标准库 os/signal 提供了对信号处理的支持,本文将详细讲解 Golang 是如何处理和响应系统信号的。

路多辛的所思所想 2849

Win10管理员权限的‘暗门’:从mmc.exe被阻止,聊聊UAC与自动提权那些事儿

本文深入解析Windows 10中UAC(用户账户控制)与自动提权机制,探讨mmc.exe被阻止的深层原因及解决方案。从UAC工作原理到自动提权机制,再到具体诊断与修复步骤,帮助用户理解并解决权限管理问题,同时平衡安全性与便利性。

weixin_30521161的博客 419

Golang `os/signal`包详解:全面掌握信号处理技巧

os/signal包是Golang标准库中的一部分,专门用于处理操作系统发出的信号。信号是一种异步事件,操作系统通过信号通知进程发生了某些特定的事件,例如用户按下Ctrl+C(SIGINT),系统发送终止信号(SIGTERM)等。使用os/signal包,我们可以捕捉到这些信号,并在程序中执行相应的处理逻辑,例如优雅地关闭服务、释放资源、重新加载配置文件等。下面是一个简单的示例,展示如何使用os/signalimport ("fmt""os""syscall""time"// 创建一个信号通道。

walkskyer的博客 1735

eQTL:连接突变与基因表达的桥梁

欢迎关注”生信修炼手册”!在高等生物中,很多的重要性状都为数量形状,比如农作物的产量,人类复杂疾病(高血液,糖尿病)等等。对于这些数量性状而言,往往受到多个基因的调控作用。为了更好的开展...

庐州月光的博客 7070

基于微信小程序的答题系统

学习视频:《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!5812)]《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

2401_83330193的博客 499

Go并发编程信号

本文介绍了操作系统信号的异步通信机制及其在Go语言中的实现方式。信号通过软件模拟硬件中断,用于通知事件发生,如键盘输入(Ctrl-c)或kill命令。Go语言通过os/signal包处理信号,Notify函数将指定信号放入通道供程序处理,Stop函数可取消自定义处理。文章详细说明了信号处理流程,包括信号捕获、忽略和默认操作,并提供了完整的代码示例展示如何创建多个信号接收通道以及如何优雅地停止信号处理。

不愿言弃-念何的博客 730

DDS协议--[第一章][概述]

Data Distribute Service,数据分发服务:数据分发服务(DDS™)是一个由对象管理组(OMG)发布的以数据为中心的中间件协议和API标准。DDS集成系统中的各个组件,提供低延迟数据连接、高可靠性以及高可扩展体系结构,以适应商业级物联网(IoT)应用程序的需求。

qq_41816308的博客 1153

7天玩转 Golang 标准库之 os

本文介绍了Golang中os标准库的基础和高级应用。基础部分涵盖文件读写(ioutil.Read/WriteFile)、环境变量操作(Setenv/Getenv)和命令行参数获取(os.Args)。高级应用包括进程管理(os/exec创建子进程)、信号处理(os/signal捕获SIGINT/SIGTERM)和文件锁(syscall.Flock实现互斥访问)。这些功能使Go程序能有效与操作系统交互,适合开发系统工具和后台服务。

weixin_50902344的博客 501

数据结构之博弈树搜索(深度优先搜索)

数据结构之博弈树搜索(深度优先搜索)

LucianaiB的博客 1526

18. 从 SAP Fiori Elements List Report 中的图片显示,谈谈背后的 XML Template 设计机制

至此,Fiori Elements List Report 这个模版里,图片显示的原理,笔者已经从开发人员层面需要定义的注解,和 Fiori Elements 框架层面如何解析这些注解,这两方面做了深入介绍。从本文开始,我们从 Fiori Elements 预制的标准 XML Template 模版的设计,来介绍我们在最终 Fiori Elements 页面看到的产品图标,是如何渲染出来的。但是,List Report 里产品的图标显示,到底是上面这些 XML 文件里的哪一个里定义的呢?

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 607

掌控程序生命线:深入解析 Go 语言 ossignal 库

深入解析Go语言os/signal库 本文详细介绍了Go语言标准库os/signal的核心功能和使用方法,帮助开发者优雅处理程序中断信号。主要内容包括: 核心知识 信号机制原理及作用 关键数据结构和函数:os.Signal接口、Notify()和Stop()方法 实战应用 捕获Ctrl+C中断信号的基础示例 HTTP服务器优雅关闭的实现 多信号处理与自定义逻辑 常见问题解答 信号处理失效原因分析 跨平台信号差异对比表 信号默认行为限制说明 最佳实践 使用缓冲通道避免信号丢失 清理逻辑超时控制 信号处理优先级

Tekin 是深耕技术 20 年的全栈实战派专家,精通 Go/Python/Java 等多语言开发。博客专注技术原理与实战结合,深度解析 Python 高阶编程、Go 语言架构、数据库优化等硬核内容。涵盖并发编程、机器学习、云原生等前沿领域,通过真实案例拆 1328

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Go算是最敷衍的OS包的讲解,包含(exec,signal,user)

Go的基础标准库 OS(包含exec,user,signal)

Yaoisss的博客 837

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Go语言开发(十三)、Go语言常用标准库三

Go语言开发(十三)、Go语言常用标准库三 一、sync 1、sync简介 sync提供基本的同步原语,如sync.Mutex,sync.RWMutex,sync.Once,sync.Cond,sync.Waitgroup,除了Once和WaitGroup类型外,大多数类型都供低级库使用。Go语言中,不要通过共享内存通信,而要通过通信共享内存,通过Channel和沟通可以更好地完成更高级别的同步。...

weixin_33725239的博客 544

Camera2Demo

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

Golang标准库:使用 os/exec 创建进程、终止进程代码示例

包,我们可以创建和控制外部进程,并在需要时终止它们。如果进程在等待期间发生错误,我们将错误信息输出并返回。如果启动进程过程中发生错误,我们将错误信息输出并返回。命令,等待5秒钟后进程完成。然后,会终止该进程并输出相应的状态信息。函数根据进程 ID(PID)获取进程对象。最后,我们打印出相应的状态信息,以展示进程的启动、完成和终止过程。在这个示例中,我们首先导入了需要使用的包,包括。然后,我们等待进程完成,使用命令对象的。运行后,会创建一个新的进程执行。接下来,我们使用命令对象的。完成进程后,我们使用。

学亮编程手记 986

go语言试用标准c 库,Go语言开发(十三)、Go语言常用标准库三

Go语言开发(十三)、Go语言常用标准库三一、sync1、sync简介sync提供基本的同步原语,如sync.Mutex,sync.RWMutex,sync.Once,sync.Cond,sync.Waitgroup,除了Once和WaitGroup类型外,大多数类型都供低级库使用。Go语言中,不要通过共享内存通信,而要通过通信共享内存,通过Channel和沟通可以更好地完成更高级别的同步。typ...

weixin_36204626的博客 403

Go语言跨平台开发实战:从原理到部署

跨平台开发是现代软件开发的核心需求之一,其本质是通过抽象层屏蔽不同操作系统的差异。Go语言通过静态编译、交叉编译工具链和标准库抽象等设计,实现了真正的"一次编写,到处运行"。静态编译将依赖打包成单一二进制,避免了运行时环境依赖;交叉编译工具链支持在单一平台生成多平台可执行文件;标准库对文件路径、网络通信等做了统一封装。这些特性使Go成为云原生、微服务等场景的理想选择,特别是在容器化和持续集成(CI)环境中优势明显。本文通过Windows到Linux的实战案例,展示如何利用条件编译、统一路径处理等技巧构建健壮

weixin_34159110的博客 311

Go环境搭建与入门

本文参考了Go官方文档(go.dev/doc)、Go官方入门教程(go.dev/doc/tutorial/getting-started)以及Go语言规范,为初学者提供从零开始的完整入门指南。

星航夜空的帆舟 393

Go语言实现安全WebSocket实时聊天:JWT身份验证与并发管理实战

WebSocket协议作为HTTP的补充,解决了传统请求-响应模式无法实现服务器主动推送的痛点,为实时双向通信提供了标准化的解决方案。其核心原理是在单个TCP连接上建立全双工通信通道,通过一次HTTP握手升级协议,后续即可实现低延迟的数据帧交换。这一技术价值在于能够显著降低服务器负载和网络延迟,广泛应用于即时通讯、在线协作、实时数据监控等场景。在实现WebSocket服务时,身份验证与并发管理是关键挑战。JSON Web Token(JWT)作为一种无状态的身份验证机制,通过自包含的签名令牌解决了WebSo

weixin_30603633的博客 365

autopprof核心原理深度解析:信号处理与pprof集成终极指南

**autopprof** 是一款专为Go语言开发者设计的性能分析工具,它通过巧妙的信号处理机制与标准pprof库的无缝集成,让性能分析变得前所未有的简单!🚀 本文将深入解析autopprof的核心原理,带你了解这个让Go性能分析变得轻松愉快的秘密武器。 ## 🔍 autopprof是什么? autopprof是一个开发时性能分析库,它的核心使命是**简化Go程序的性能分析流程**。传统的

gitblog_00112的博客 338

Go 语言从入门到进阶 | 第 25 章:构建 Go 微服务

本文是Go语言微服务开发指南的第25章,主要讲解如何基于标准库构建生产级微服务。作者耿雨飞要求读者具备Go基础(1.26.2版本),熟悉net/http、context等核心包。 内容涵盖RESTful API设计、路由增强(Go 1.22+支持方法匹配和路径参数)、中间件链实现、JSON序列化、优雅关闭、配置管理(遵循12-Factor原则)以及健康检查和运行时指标暴露(使用expvar)。重点强调仅依赖标准库开发,通过分析关键源码(如server.go、request.go等)深入理解实现原理。 学习目

weixin_43674738的博客 47
上一篇: Go语言标准库学习之encoding/gob——Go语言Gob流的管理
下一篇: Go语言标准库学习之sync二(通过sync.Pool大幅度提升程序运行性能)
random_w
博客等级 码龄9年 130粉丝 168原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值