Golang信號處理和優(yōu)雅退出守護進程

Golang中的信號處理

  • 信號類型
個平臺的信號定義或許有些不同嫉入。下面列出了POSIX中定義的信號。
Linux 使用34-64信號用作實時系統(tǒng)中爱葵。
命令 man signal 提供了官方的信號介紹惜浅。
在POSIX.1-1990標準中定義的信號列表
信號 動作 說明
SIGHUP 1 Term 終端控制進程結(jié)束(終端連接斷開)
SIGINT 2 Term 用戶發(fā)送INTR字符(Ctrl+C)觸發(fā)
SIGQUIT 3 Core 用戶發(fā)送QUIT字符(Ctrl+/)觸發(fā)
SIGILL 4 Core 非法指令(程序錯誤酣溃、試圖執(zhí)行數(shù)據(jù)段、棧溢出等)
SIGABRT 6 Core 調(diào)用abort函數(shù)觸發(fā)
SIGFPE 8 Core 算術(shù)運行錯誤(浮點運算錯誤、除數(shù)為零等)
SIGKILL 9 Term 無條件結(jié)束程序(不能被捕獲窍侧、阻塞或忽略)
SIGSEGV 11 Core 無效內(nèi)存引用(試圖訪問不屬于自己的內(nèi)存空間停撞、對只讀內(nèi)存空間進行寫操作)
SIGPIPE 13 Term 消息管道損壞(FIFO/Socket通信時瓷蛙,管道未打開而進行寫操作)
SIGALRM 14 Term 時鐘定時信號
SIGTERM 15 Term 結(jié)束程序(可以被捕獲悼瓮、阻塞或忽略)
SIGUSR1 30,10,16 Term 用戶保留
SIGUSR2 31,12,17 Term 用戶保留
SIGCHLD 20,17,18 Ign 子進程結(jié)束(由父進程接收)
SIGCONT 19,18,25 Cont 繼續(xù)執(zhí)行已經(jīng)停止的進程(不能被阻塞)
SIGSTOP 17,19,23 Stop 停止進程(不能被捕獲、阻塞或忽略)
SIGTSTP 18,20,24 Stop 停止進程(可以被捕獲艰猬、阻塞或忽略)
SIGTTIN 21,21,26 Stop 后臺程序從終端中讀取數(shù)據(jù)時觸發(fā)
SIGTTOU 22,22,27 Stop 后臺程序向終端中寫數(shù)據(jù)時觸發(fā)
  • 在SUSv2和POSIX.1-2001標準中的信號列表:
信號 動作 說明
SIGTRAP 5 Core Trap指令觸發(fā)(如斷點横堡,在調(diào)試器中使用)
SIGBUS 0,7,10 Core 非法地址(內(nèi)存地址對齊錯誤)
SIGPOLL Term Pollable event (Sys V). Synonym for SIGIO
SIGPROF 27,27,29 Term 性能時鐘信號(包含系統(tǒng)調(diào)用時間和進程占用CPU的時間)
SIGSYS 12,31,12 Core 無效的系統(tǒng)調(diào)用(SVr4)
SIGURG 16,23,21 Ign 有緊急數(shù)據(jù)到達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個信號值,這是因為這些信號值與平臺相關(guān)食听,將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列為操作系統(tǒng)收到信號后的動作,Term表明默認動作為終止進程樱报,Ign表明默認動作為忽略該信號葬项,Core表明默認動作為終止進程同時輸出core dump,Stop表明默認動作為停止進程迹蛤。
第4列為對信號作用的注釋性說明玷室,淺顯易懂,這里不再贅述笤受。
需要特別說明的是穷缤,SIGKILL和SIGSTOP這兩個信號既不能被應用程序捕獲,也不能被操作系統(tǒng)阻塞或忽略箩兽。
  • kill pid與kill -9 pid的區(qū)別
kill pid的作用是向進程號為pid的進程發(fā)送SIGTERM(這是kill默認發(fā)送的信號)津肛,該信號是一個結(jié)束進程的信號且可以被應用程序捕獲。若應用程序沒有捕獲并響應該信號的邏輯代碼汗贫,則該信號的默認動作是kill掉進程身坐。這是終止指定進程的推薦做法。
kill -9 pid則是向進程號為pid的進程發(fā)送SIGKILL(該信號的編號為9)落包,從本文上面的說明可知部蛇,SIGKILL既不能被應用程序捕獲,也不能被阻塞或忽略咐蝇,其動作是立即結(jié)束指定進程觅闽。通俗地說侈净,應用程序根本無法“感知”SIGKILL信號黍氮,它在完全無準備的情況下晕鹊,就被收到SIGKILL信號的操作系統(tǒng)給干掉了,顯然旭寿,在這種“暴力”情況下警绩,應用程序完全沒有釋放當前占用資源的機會。事實上盅称,SIGKILL信號是直接發(fā)給init進程的肩祥,它收到該信號后后室,負責終止pid指定的進程。在某些情況下(如進程已經(jīng)hang死混狠,無法響應正常信號)岸霹,就可以使用kill -9來結(jié)束進程。
若通過kill結(jié)束的進程是一個創(chuàng)建過子進程的父進程檀蹋,則其子進程就會成為孤兒進程(Orphan Process),這種情況下云芦,子進程的退出狀態(tài)就不能再被應用進程捕獲(因為作為父進程的應用程序已經(jīng)不存在了)俯逾,不過應該不會對整個linux系統(tǒng)產(chǎn)生什么不利影響。
  • 應用程序如何優(yōu)雅退出
Linux Server端的應用程序經(jīng)常會長時間運行舅逸,在運行過程中桌肴,可能申請了很多系統(tǒng)資源,也可能保存了很多狀態(tài)琉历,在這些場景下坠七,我們希望進程在退出前,可以釋放資源或?qū)斍盃顟B(tài)dump到磁盤上或打印一些重要的日志旗笔,也就是希望進程優(yōu)雅退出(exit gracefully)彪置。
從上面的介紹不難看出,優(yōu)雅退出可以通過捕獲SIGTERM來實現(xiàn)蝇恶。具體來講拳魁,通常只需要兩步動作:
1)注冊SIGTERM信號的處理函數(shù)并在處理函數(shù)中做一些進程退出的準備。信號處理函數(shù)的注冊可以通過signal()或sigaction()來實現(xiàn)撮弧,其中潘懊,推薦使用后者來實現(xiàn)信號響應函數(shù)的設(shè)置。信號處理函數(shù)的邏輯越簡單越好贿衍,通常的做法是在該函數(shù)中設(shè)置一個bool型的flag變量以表明進程收到了SIGTERM信號授舟,準備退出。
2)在主進程的main()中贸辈,通過類似于while(!bQuit)的邏輯來檢測那個flag變量释树,一旦bQuit在signal handler function中被置為true,則主進程退出while()循環(huán)擎淤,接下來就是一些釋放資源或dump進程當前狀態(tài)或記錄日志的動作躏哩,完成這些后,主進程退出揉燃。

Go中的Signal發(fā)送和處理

  • golang中對信號的處理主要使用os/signal包中的兩個方法:
  • notify方法用來監(jiān)聽收到的信號
  • stop方法用來取消監(jiān)聽

1.監(jiān)聽全部信號

package main

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

// 監(jiān)聽全部信號
func main()  {
    //合建chan
    c := make(chan os.Signal)
    //監(jiān)聽所有信號
    signal.Notify(c)
    //阻塞直到有信號傳入
    fmt.Println("啟動")
    s := <-c
    fmt.Println("退出信號", s)
}
啟動
go run example-1.go
啟動

ctrl+c退出,輸出
退出信號 interrupt

kill pid 輸出
退出信號 terminated

2.監(jiān)聽指定信號

package main

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

// 監(jiān)聽指定信號
func main()  {
    //合建chan
    c := make(chan os.Signal)
    //監(jiān)聽指定信號 ctrl+c kill
    signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGUSR1, syscall.SIGUSR2)
    //阻塞直到有信號傳入
    fmt.Println("啟動")
    //阻塞直至有信號傳入
    s := <-c
    fmt.Println("退出信號", s)
}
啟動
go run example-2.go
啟動

ctrl+c退出,輸出
退出信號 interrupt

kill pid 輸出
退出信號 terminated

kill -USR1 pid 輸出
退出信號 user defined signal 1

kill -USR2 pid 輸出
退出信號 user defined signal 2

3.優(yōu)雅退出go守護進程

package main

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

// 優(yōu)雅退出go守護進程
func main()  {
    //創(chuàng)建監(jiān)聽退出chan
    c := make(chan os.Signal)
    //監(jiān)聽指定信號 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("執(zhí)行清理...")
    fmt.Println("結(jié)束退出...")
    os.Exit(0)
}
kill -USR1 pid 輸出
usr1 user defined signal 1

kill -USR2 pid 
usr2 user defined signal 2

kill pid 
退出 terminated
開始退出...
執(zhí)行清理...
結(jié)束退出...
執(zhí)行輸出
go run example-3.go
進程啟動...
sum: 1
sum: 2
sum: 3
sum: 4
sum: 5
sum: 6
sum: 7
sum: 8
sum: 9
usr1 user defined signal 1
sum: 10
sum: 11
sum: 12
sum: 13
sum: 14
usr2 user defined signal 2
sum: 15
sum: 16
sum: 17
退出 terminated
開始退出...
執(zhí)行清理...
結(jié)束退出...

參考

http://www.cnblogs.com/jkkkk/p/6180016.html
http://blog.csdn.net/zzhongcy/article/details/50601079
https://www.douban.com/note/484935836/
https://gist.github.com/reiki4040/be3705f307d3cd136e85#file-signal-go-L1
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末扫尺,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子炊汤,更是在濱河造成了極大的恐慌正驻,老刑警劉巖弊攘,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異姑曙,居然都是意外死亡襟交,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門伤靠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捣域,“玉大人,你說我怎么就攤上這事宴合』烂罚” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵卦洽,是天一觀的道長贞言。 經(jīng)常有香客問我,道長阀蒂,這世上最難降的妖魔是什么该窗? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蚤霞,結(jié)果婚禮上酗失,老公的妹妹穿的比我還像新娘。我一直安慰自己昧绣,他們只是感情好级零,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著滞乙,像睡著了一般奏纪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上斩启,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天序调,我揣著相機與錄音,去河邊找鬼兔簇。 笑死发绢,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的垄琐。 我是一名探鬼主播边酒,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼狸窘!你這毒婦竟也來了墩朦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤翻擒,失蹤者是張志新(化名)和其女友劉穎氓涣,沒想到半個月后牛哺,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡劳吠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年引润,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痒玩。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡淳附,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蠢古,到底是詐尸還是另有隱情奴曙,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布便瑟,位于F島的核電站缆毁,受9級特大地震影響番川,放射性物質(zhì)發(fā)生泄漏到涂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一颁督、第九天 我趴在偏房一處隱蔽的房頂上張望践啄。 院中可真熱鬧,春花似錦沉御、人聲如沸屿讽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伐谈。三九已至,卻和暖如春试疙,著一層夾襖步出監(jiān)牢的瞬間诵棵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工祝旷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留履澳,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓怀跛,卻偏偏與公主長得像距贷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吻谋,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 又來到了一個老生常談的問題忠蝗,應用層軟件開發(fā)的程序員要不要了解和深入學習操作系統(tǒng)呢? 今天就這個問題開始漓拾,來談談操...
    tangsl閱讀 4,088評論 0 23
  • 信號(signal)是一種軟件中斷,它提供了一種處理異步事件的方法闽撤,也是進程間惟一的異步通信方式得哆。在Linux系統(tǒng)...
    夏大王2019閱讀 996評論 0 1
  • 有些女生可能有個疑問贩据?我們都獨立了,財富自由了闸餐,我們需要要男人干什么饱亮?首先說一下,你要真有這種思想舍沙,我估計...
    立馬晶晶閱讀 370評論 0 1
  • 因為明天要進行這學期的期中考試近上,今天晚上老師布置了一些重要的作業(yè)讓孩子做,兒子做到9:30分的時候困的不行了拂铡,眼睛...
    劉家豪媽媽閱讀 203評論 0 0
  • 生日之前壹无,老父親打電話說:“星期天你在家吧,我們來感帅,給你送雞蛋來斗锭。”淚禁不住……生日對我們這個年齡的人來說失球,總是和...
    漁得漁樵得樵閱讀 278評論 0 1