[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標准中定義的信號列表

信號 動作 說明
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)

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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM