[golang]golang signal.Notify 信号,如何优雅的退出

[golang]golang signal.Notify 信号,如何优雅的退出

golang 中的signal 包的Notify函数

函数声明为

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

官方描述:

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

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

ch := make(chan os.Signal, 1)
    signal.Notify(ch, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP, syscall.SIGUSR1)
    for {
        s := <-ch
        switch s {
        case syscall.SIGQUIT:
            log.Infof("SIGSTOP")
            return
        case syscall.SIGSTOP:
            log.Infof("SIGSTOP")
            return
        case syscall.SIGHUP:
            log.Infof("SIGHUP")
            return
        case syscall.SIGKILL:
            log.Infof("SIGKILL")
            return
        case syscall.SIGUSR1:
            log.Infof("SIGUSR1")
            return
        default:
            log.Infof("default")
            return
        }
    }

以上代码告诉 signal ,将对应的信号通知 ch,然后在 for 循环中针对不同信号做不同的处理, for 循环为死循环。

 

优雅退出go守护进程

package main
 
import (
        "fmt"
        "os"
        "os/signal"
        "syscall"
        "time"
)
 
func main() {
        //创建监听退出chan
        c := make(chan os.Signal)
        //监听指定信号 ctrl+c kill
        signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, 
                         syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2)
        go func() {
                for s := range c {
                        switch s {
                        case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
                                fmt.Println("Program Exit...", s)
                                GracefullExit()
                        case syscall.SIGUSR1:
                                fmt.Println("usr1 signal", s)
                        case syscall.SIGUSR2:
                                fmt.Println("usr2 signal", s)
                        default:
                                fmt.Println("other signal", s)
                        }
                }
        }()
 
        fmt.Println("Program Start...")
        sum := 0
        for {
                sum++
                fmt.Println("sum:", sum)
                time.Sleep(time.Second)
        }
}
 
func GracefullExit() {
        fmt.Println("Start Exit...")
        fmt.Println("Execute Clean...")
        fmt.Println("End Exit...")
        os.Exit(0)
}

Linux Signal及Golang中的信号处理

信号(Signal)是Linux, 类Unix和其它POSIX兼容的操作系统中用来进程间通讯的一种方式。一个信号就是一个异步的通知,发送给某个进程,或者同进程的某个线程,告诉它们某个事件发生了。
当信号发送到某个进程中时,操作系统会中断该进程的正常流程,并进入相应的信号处理函数执行操作,完成后再回到中断的地方继续执行。
如果目标进程先前注册了某个信号的处理程序(signal handler),则此处理程序会被调用,否则缺省的处理程序被调用。

https://colobu.com/2015/10/09/Linux-Signals/

信号类型

个平台的信号定义或许有些不同。下面列出了POSIX中定义的信号。
Linux 使用34-64信号用作实时系统中。
命令man 7 signal提供了官方的信号介绍。

在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非法地址(内存地址对齐错误)
SIGPOLL TermPollable 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)

Windows中没有SIGUSR1,可以用SIGBREAK或者SIGINT代替。

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值