【Golang】——信號處理

一、前言

Golang 的系統信號處理主要涉及os包、os.signal包以及syscall包.其中最主要的函數是signal包中的Notify函數:

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

該函數會將進程收到的系統Signal轉發給channel c.轉發哪些信號由該函數的可變參數決定,如果你沒有傳入sig參數,那麼Notify會將系統收到的所有信號轉發給c.如果你像下面這樣調用Notify:

signal.Notify(c, syscall.SIGINT, syscall.SIGUSR1, syscall.SIGUSR2)

則Go只會關注你傳入的Signal類型,其他Signal將會按照默認方式處理,大多都是進程退出.因此你需要在Notify中傳入你要關注和處理的Signal類型,也就是攔截它們,提供自定義處理函數來改變它們的行爲.

二、信號類型

      不同平臺的信號定義或許有些不同.下面列出了POSIX中定義的信號. Linux 使用34-64信號用作實時系統中. 命令 man signal 提供了官方的信號介紹. 在POSIX.1-1990標準中定義的信號列表。

第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這兩個信號既不能被應用程序捕獲,也不能被操作系統阻塞或忽略.
信號 動作 說明
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)

 

四、Go中的Signal發送和處理

  • golang中對信號的處理主要使用os/signal包中的兩個方法:
  • notify方法用來監聽收到的信號
  • stop方法用來取消監聽
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, syscall.SIGUSR1, syscall.SIGUSR2)
        go func() {
            for s := range c {
                switch s {
                case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
                    fmt.Println("退出", s)
                    ExitFunc()
                case syscall.SIGUSR1:
                    fmt.Println("usr1", s)
                case syscall.SIGUSR2:
                    fmt.Println("usr2", s)
                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)
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章