golang信号处理

信号是IPC之一,下面是常用的信号列表

信号 动作 说明
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通信时,管道未打开而进行写操作)
SIGTERM 15 Term 结束程序(可以被捕获、阻塞或忽略)
SIGUSR1 30,10,16 Term 用户保留
SIGUSR2 31,12,17 Term 用户保留
SIGCHLD 20,17,18 Ign 子进程结束(由父进程接收)
SIGTSTP 18,20,24 Stop 停止进程(可以被捕获、阻塞或忽略)

我们已经知道信号是IPC方式之一,那么在go中,我们就可以利用信号来优化和完善我们的程序。

熟悉nginx的可以知道 nginx -s 其他命令其实就是利用信号来实现master和worker 进程间的通信。我们也可以模仿nginx来实现go进程通信

场景 1 ,以非守护进程的方式运行go 程序

go run main.go

当我们执行 Ctrl+C 动作时,会触发SIGINT 信号,我们可以捕获这一信号来进行相应的处理。
package main

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

func main()  {
    c := make(chan os.Signal)
    stop := make(chan int)
    signal.Notify(c, syscall.SIGINT)
    go func() {
        for  {
            select {
            case s := <-c:
                fmt.Println(fmt.Sprintf("捕获到SIGINT:%s",s))
                //do something
                os.Exit(0)
            }
        }
    }()

    <-stop

}

执行 Ctrl+C
output : ^C捕获到SIGINT:interrupt

场景 2 ,以守护进程的方式运行go 程序

go run main.go &

注意:执行 kill -9 pid 时,SIGKILL信号是不能被捕获的

假设该程序的PID为233333,我们可以学习PHP的fmp优雅重启来捕获SIGUSR2 信号来自定义后面的重启处理

注意:SIGUSR2 在DARWIN 下 值为31,LINUX_AMD64 为 12

step1: go run main.go &
step2: ps -ef | grep 'go run main.go'
step3: kill -31 PID

如上就是一个乞丐版平滑重载配置

package main

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

func main()  {
    c := make(chan os.Signal)
    stop := make(chan int)
    signal.Notify(c, syscall.SIGUSR2)
    go func() {
        for  {
            select {
            case s := <-c:
                fmt.Println(fmt.Sprintf("捕获到SIGUSR2,正在重启配置:%s",s))
                //do something
                fmt.Println("我已经重新加载了配置")
                os.Exit(0)
            }
        }
    }()

    <-stop

}

你可能感兴趣的:(golang信号处理)