Go Signal信号处理
前言
信号(Signal)是Linux, 类Unix和其它POSIX兼容的操作系统中用来进程间通讯的一种方式。对于Linux系统来说,信号就是软中断,用来通知进程发生了异步事件。
当信号发送到某个进程中时,操作系统会中断该进程的正常流程,并进入相应的信号处理函数执行操作,完成后再回到中断的地方继续执行。
有时候我们想在Go程序中处理Signal信号,比如收到SIGTERM
信号后优雅的关闭程序,以及 goroutine结束通知等。
Go 语言提供了对信号处理的包(os/signal)。
Go 中对信号的处理主要使用os/signal包中的两个方法:一个是notify方法用来监听收到的信号;一个是 stop方法用来取消监听。
Go信号通知机制可以通过往一个channel中发送os.Signal
实现。
信号类型
个平台的信号定义或许有些不同。下面列出了POSIX中定义的信号。
Linux 使用34-64信号用作实时系统中。
命令 man signal 提供了官方的信号介绍。
在POSIX.1-1990标准中定义的信号列表
信号 | 值 | 动作 | 说明 |
---|---|---|---|
SIGHUP | 1 | Term | 终端控制进程结束(终端连接断开) |
SIGINT | 2 | Term | 用户发送INTR字符(Ctrl+C)触发 |
SIGQUIT | 3 | Core | 用户发送QUIT字符(Ctrl+/)触发 |
SIGILL | 4 | Core | 非法指令(程序错误、试图执行数据段、栈溢出等) |
SIGABRT | 6 | Core | 调用abort函数触发 |
SIGFPE | 8 | Core | 算术运行错误(浮点运算错误、除数为零等) |
SIGKILL | 9 | Term | 无条件结束程序(不能被捕获、阻塞或忽略) |
SIGSEGV | 11 | Core | 无效内存引用(试图访问不属于自己的内存空间、对只读内存空间进行写操作) |
SIGPIPE | 13 | Term | 消息管道损坏(FIFO/Socket通信时,管道未打开而进行写操作) |
SIGALRM | 14 | Term | 时钟定时信号 |
SIGTERM | 15 | Term | 结束程序(可以被捕获、阻塞或忽略) |
SIGUSR1 | 30,10,16 | Term | 用户保留 |
SIGUSR2 | 31,12,17 | Term | 用户保留 |
SIGCHLD | 20,17,18 | Ign | 子进程结束(由父进程接收) |
SIGCONT | 19,18,25 | Cont | 继续执行已经停止的进程(不能被阻塞) |
SIGSTOP | 17,19,23 | Stop | 停止进程(不能被捕获、阻塞或忽略) |
SIGTSTP | 18,20,24 | Stop | 停止进程(可以被捕获、阻塞或忽略) |
SIGTTIN | 21,21,26 | Stop | 后台程序从终端中读取数据时触发 |
SIGTTOU | 22,22,27 | Stop | 后台程序向终端中写数据时触发 |
- 在SUSv2和POSIX.1-2001标准中的信号列表:
信号 | 值 | 动作 | 说明 |
---|---|---|---|
SIGTRAP | 5 | Core | Trap指令触发(如断点,在调试器中使用) |
SIGBUS | 0,7,10 | Core | 非法地址(内存地址对齐错误) |
SIGPOLL | Term | Pollable event (Sys V). Synonym for SIGIO | |
SIGPROF | 27,27,29 | Term | 性能时钟信号(包含系统调用时间和进程占用CPU的时间) |
SIGSYS | 12,31,12 | Core | 无效的系统调用(SVr4) |
SIGURG | 16,23,21 | Ign | 有紧急数据到达Socket(4.2BSD) |
SIGVTALRM | 26,26,28 | Term | 虚拟时钟信号(进程占用CPU的时间)(4.2BSD) |
SIGXCPU | 24,24,30 | Core | 超过CPU时间资源限制(4.2BSD) |
SIGXFSZ | 25,25,31 | Core | 超过文件大小资源限制(4.2BSD) |
第1列为信号名;
第2列为对应的信号值,需要注意的是,有些信号名对应着3个信号值,这是因为这些信号值与平台相关,将man手册中对3个信号值的说明摘出如下,the first one is usually valid for alpha and sparc, the middle one for i386, ppc and sh, and the last one for mips.
第3列为操作系统收到信号后的动作,Term表明默认动作为终止进程,Ign表明默认动作为忽略该信号,Core表明默认动作为终止进程同时输出core dump,Stop表明默认动作为停止进程。
第4列为对信号作用的注释性说明,浅显易懂,这里不再赘述。
需要特别说明的是,SIGKILL和SIGSTOP这两个信号既不能被应用程序捕获,也不能被操作系统阻塞或忽略。
Notify 示例
新建一个测试文件 test5.go
package mainimport "fmt"
import "os"
import "os/signal"
import "syscall"func main() {// 创建一个os.Signal channelsigs := make(chan os.Signal, 1)//创建一个bool channeldone := make(chan bool, 1)//注册要接收的信号,syscall.SIGINT:接收ctrl+c ,syscall.SIGTERM:程序退出//信号没有信号参数表示接收所有的信号signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)//此goroutine为执行阻塞接收信号。一旦有了它,它就会打印出来。//然后通知程序可以完成。go func() {sig := <-sigsfmt.Println(sig)done <- true}()//程序将在此处等待,直到它预期信号(如Goroutine所示)//在“done”上发送一个值,然后退出。fmt.Println("awaiting signal")<-donefmt.Println("exiting")
}
执行 go run test5.go 再敲入 ctrl+c,程序会输出
awaiting signal
interrupt
exiting
如果用kill pid 结束程序,则输出
awaiting signal
Terminated
取消监听 stop
修改代码,增加 signal.Stop(sigs)
package mainimport "fmt"
import "os"
import "os/signal"
import "syscall"func main() {// 创建一个os.Signal channelsigs := make(chan os.Signal, 1)//创建一个bool channeldone := make(chan bool, 1)//注册要接收的信号,syscall.SIGINT:接收ctrl+c ,syscall.SIGTERM:程序退出//信号没有信号参数表示接收所有的信号signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)//此goroutine为执行阻塞接收信号。一旦有了它,它就会打印出来。//然后通知程序可以完成。go func() {sig := <-sigsfmt.Println(sig)done <- true}()//不允许继续往sigs中存入内容signal.Stop(sigs)//程序将在此处等待,直到它预期信号(如Goroutine所示)//在“done”上发送一个值,然后退出。fmt.Println("awaiting signal")<-donefmt.Println("exiting")
}
执行 go run test5.go 再敲入 ctrl+c,程序输出仅awaiting signal。不会输出signal.Stop(sigs)之后的内容。
Go 优雅重启
如何实现优雅地重启一个Go网络程序呢。主要要解决两个问题:
1、重启进程不需要关闭端口。
2、保持已有的连接请求不中断,让其执行完成或超时。
大概个执行步骤:
fork一个继承侦听套接字的新进程。
子进程初始化并开始接受套接字上的连接。
子进程向父进程发信号,通知父进程停止接收连接并终止。
具体实现请阅读文章Graceful Restart in Golang中提供了一种方式。
参考
https://golang.org/pkg/os/signal/
https://grisha.org/blog/2014/06/03/graceful-restart-in-golang/
https://play.golang.org/p/BlkqAtKsxo
links
- 目录
Go Signal信号处理相关推荐
- c语言线程唤醒signal,多线程编程与signal信号处理
对于多线程编程时候,对于signal传递的信号处理函数对于各个线程是共享的,虽然各个线程可以设置自己的屏蔽字.如下面所示代码.两个线程中,每个线程有一个signal接受信号,但是实际上执行时每个线程会 ...
- 嵌入式Linux系统编程学习之十四signal信号处理机制
可以用函数 signal 注册一个信号处理函数,原型为: #include <signal.h>typedef void(*sighandler_t)(int); //函数指针 voi ...
- Signal信号处理
在goahead的linux模块main.c 文件中,main函数中出现了以下三个语句: signal(SIGPIPE, SIG_IGN); signal(SIGINT, sigintHandle ...
- scipy.signal信号处理的库(笔记06)
信号处理(scipy.signal) 网址:https://docs.scipy.org/doc/scipy/reference/signal.html#scipy.signal 卷积 convolv ...
- 如何在GDB中忽略Signal信号处理
在使用GDB调试C/C++程序时,如果刚好程序中需要对特殊Signal处理,则在调试这类应用时需要GDB忽略对该Signal的处理.本文来自GBD官方文档的翻译,仅供参考. 信号(Signals) 信 ...
- Python signal 信号处理模块
Table of Contents 1. signal模块简介 1.1. signal简单示例 1.2. signal说明 1.2.1. 基本的信号名 1.2.2. 常用信号处理函数 2. signa ...
- golang signal 信号处理
目录 信号类型 golang 信号发送和处理 信号类型 个平台的信号定义或许有些不同.下面列出了POSIX中定义的信号. Linux 使用34-64信号用作实时系统中. 命令 man signal 提 ...
- 以SIGSEGV为例详解信号处理(与栈回溯)
以SIGSEGV为例详解信号处理(与栈回溯) 信号是内核提供的向用户态进程发送信息的机制, 常见的有使用SIGUSR1唤醒用户进程执行子程序或发生段错误时使用SIGSEGV保存用户错误现场. 本文以S ...
- linux 信号处理函数详解
转自:http://blog.csdn.NET/sddzycnqjn/article/details/7285760 1. 信号概念 信号是进程在运行过程中,由自身产生或由进程外部发过来的消息(事件 ...
最新文章
- 如何获得更多的自由开发者客户
- 聊聊《柒个我》这部剧
- 推荐两本旧书 recommend two CM books,which are not up-to-date
- VS2010 断点无效肿么办?
- 马哥-51CTO-Linux培训-0910-程序包管理
- 关于java数组拷贝的性能
- Bash脚本教程之算数运算
- kibana 查看索引库中文档个数_百度索引量是什么意思?和百度收录量的区别。...
- MyBatis 实例
- exe文件注册服务的方法
- BZOJ 2763 飞行线路
- 设计模式之GOF23享元模式
- MVC3+EF4.1学习系列(八)-----利用Repository and Unit of Wor
- VML编程之------background背景《VML极道教程》原著:沐缘华
- 几何画板如何生成三角函数图像
- java宿舍信息管理系统_Java宿舍管理系统
- 运营Tumblr的几个建议-教你成为tumblr达人
- C++课程设计:学生管理系统
- android开机卡logo,logcat怎么抓log
- 数字孪生核电站促进界面监测的应用实践