本篇內容介紹了“Linux系統中的信號類(lèi)型以及Go中的信號發(fā)送和處理”的有關(guān)知識,在實(shí)際案例的操作過(guò)程中,不少人都會(huì )遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學(xué)有所成!
各操作系統的信號定義或許有些不同。下面列出了POSIX中定義的信號。
在linux中使用34-64信號用作實(shí)時(shí)系統中。
命令 man 7 signal 提供了官方的信號介紹。也可以是用kill -l來(lái)快速查看
列表中,編號為1 ~ 31的信號為傳統UNIX支持的信號,是不可靠信號(非實(shí)時(shí)的),編號為32 ~ 63的信號是后來(lái)擴充的,稱(chēng)做可靠信號(實(shí)時(shí)信號)。不可靠信號和可靠信號的區別在于前者不支持排隊,可能會(huì )造成信號丟失,而后者不會(huì )。
Linux支持的標準信號有以下一些,一個(gè)信號有多個(gè)值的是因為不同架構使用的值不一樣,比如x86, ia64,ppc, s390, 有3個(gè)值的,第一個(gè)值是slpha和sparc,中間的值是 ix86,
ia64, ppc, s390, arm和sh, 最后一個(gè)值是對mips的,連字符-表示這個(gè)架構是缺這個(gè)信號支持的,
第1列為信號名;
第2列為對應的信號值,需要注意的是,有些信號名對應著(zhù)3個(gè)信號值,這是因為這些信號值與平臺相關(guān),將man手冊中對3個(gè)信號值的說(shuō)明摘出如下,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列為操作系統收到信號后的動(dòng)作,Term表明默認動(dòng)作為終止進(jìn)程,Ign表明默認動(dòng)作為忽略該信號,Core表明默認動(dòng)作為終止進(jìn)程同時(shí)輸出core dump,Stop表明默認動(dòng)作為停止進(jìn)程。
第4列為對信號作用的注釋性說(shuō)明。
Signal Value Action Comment ---------------------------------------------------------------------- SIGHUP 1 Term Hangup detected on controlling terminal or death of controlling process SIGINT 2 Term Interrupt from keyboard SIGQUIT 3 Core Quit from keyboard SIGILL 4 Core Illegal Instruction SIGABRT 6 Core Abort signal from abort(3) SIGFPE 8 Core Floating point exception SIGKILL 9 Term Kill signal SIGSEGV 11 Core Invalid memory reference SIGPIPE 13 Term Broken pipe: write to pipe with no readers SIGALRM 14 Term Timer signal from alarm(2) SIGTERM 15 Term Termination signal SIGUSR1 30,10,16 Term User-defined signal 1 SIGUSR2 31,12,17 Term User-defined signal 2 SIGCHLD 20,17,18 Ign Child stopped or terminated SIGCONT 19,18,25 Cont Continue if stopped SIGSTOP 17,19,23 Stop Stop process SIGTSTP 18,20,24 Stop Stop typed at tty SIGTTIN 21,21,26 Stop tty input for background process SIGTTOU 22,22,27 Stop tty output for background process
SIGKILL和SIGSTOP信號是不能被捕獲,阻塞和忽略的。
Signal Value Action Comment -------------------------------------------------------------------- SIGBUS 10,7,10 Core Bus error (bad memory access) SIGPOLL Term Pollable event (Sys V). Synonym for SIGIO SIGPROF 27,27,29 Term Profiling timer expired SIGSYS 12,-,12 Core Bad argument to routine (SVr4) SIGTRAP 5 Core Trace/breakpoint trap SIGURG 16,23,21 Ign Urgent condition on socket (4.2BSD) SIGVTALRM 26,26,28 Term Virtual alarm clock (4.2BSD) SIGXCPU 24,24,30 Core CPU time limit exceeded (4.2BSD) SIGXFSZ 25,25,31 Core File size limit exceeded (4.2BSD)
早在Linux 2.2SIGSYS, SIGXCPU, SIGXFSZ和SIGBUS(非sparc和mips架構)的默認操作就是終止進(jìn)程(但是不產(chǎn)生coredump)
在一些unix系統中SIGXCPU和SIGXFSZ信號是用來(lái)終止進(jìn)程的,也是不產(chǎn)生coredunp,從Linux 2.4開(kāi)始這些信號會(huì )產(chǎn)生coredump了。
Signal Value Action Comment -------------------------------------------------------------------- SIGIOT 6 Core IOT trap. A synonym for SIGABRT SIGEMT 7,-,7 Term SIGSTKFLT -,16,- Term Stack fault on coprocessor (unused) SIGIO 23,29,22 Term I/O now possible (4.2BSD) SIGCLD -,-,18 Ign A synonym for SIGCHLD SIGPWR 29,30,19 Term Power failure (System V) SIGINFO 29,-,- A synonym for SIGPWR SIGLOST -,-,- Term File lock lost SIGWINCH 28,28,20 Ign Window resize signal (4.3BSD, Sun) SIGUNUSED -,31,- Term Unused signal (will be SIGSYS)
信號29是在alpha中是 SIGINFO或SIGPWR,但是在sparc中是SIGLOST。
SIGEMT沒(méi)有在POSIX.1-2001中定義, 但是在大多數Unix戲中是沒(méi)有的,他的默認處理方式是coredump并且終止進(jìn)程。
SIGPWR(沒(méi)有在POSIX.1-2001中定義)他的默認處理方式是忽略。
SIGIO(沒(méi)有在POSIX.1-2001中定義)在一些Unix系統中的處理方式也是忽略。
kill pid的作用是向進(jìn)程號為pid的進(jìn)程發(fā)送SIGTERM(這是kill默認發(fā)送的信號),該信號是一個(gè)結束進(jìn)程的信號且可以被應用程序捕獲。若應用程序沒(méi)有捕獲并響應該信號的邏輯代碼,則該信號的默認動(dòng)作是kill掉進(jìn)程。這是終止指定進(jìn)程的推薦做法。
kill -9 pid則是向進(jìn)程號為pid的進(jìn)程發(fā)送SIGKILL(該信號的編號為9),從本文上面的說(shuō)明可知,SIGKILL既不能被應用程序捕獲,也不能被阻塞或忽略,其動(dòng)作是立即結束指定進(jìn)程。通俗地說(shuō),應用程序根本無(wú)法“感知”SIGKILL信號,它在完全無(wú)準備的情況下,就被收到SIGKILL信號的操作系統給干掉了,顯然,在這種“暴力”情況下,應用程序完全沒(méi)有釋放當前占用資源的機會(huì )。事實(shí)上,SIGKILL信號是直接發(fā)給init進(jìn)程的,它收到該信號后,負責終止pid指定的進(jìn)程。在某些情況下(如進(jìn)程已經(jīng)hang死,無(wú)法響應正常信號),就可以使用kill -9來(lái)結束進(jìn)程。
若通過(guò)kill結束的進(jìn)程是一個(gè)創(chuàng )建過(guò)子進(jìn)程的父進(jìn)程,則其子進(jìn)程就會(huì )成為孤兒進(jìn)程(Orphan Process),這種情況下,子進(jìn)程的退出狀態(tài)就不能再被應用進(jìn)程捕獲(因為作為父進(jìn)程的應用程序已經(jīng)不存在了),不過(guò)應該不會(huì )對整個(gè)linux系統產(chǎn)生什么不利影響。
有時(shí)候我們想在Go程序中處理Signal信號,比如收到 SIGTERM 信號后優(yōu)雅的關(guān)閉程序(參看下一節的應用)。Go信號通知機制可以通過(guò)往一個(gè)channel中發(fā)送 os.Signal 實(shí)現。首先我們創(chuàng )建一個(gè)os.Signal channel,然后使用 signal.Notify 注冊要接收的信號。
package main import ( "fmt" "os" "os/signal" "syscall" ) func main() { sigs := make(chan os.Signal, 1) done := make(chan bool, 1) // signal.Notify(c) signal.Notify(sigs, os.Interrupt, os.Kill, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGINT, syscall.SIGTERM) go func() { sig := <-sigs fmt.Println(sig) done <- true }() fmt.Println("wait for signal") <- done fmt.Println("got signal and exit") fmt.Println("run done") }
首先什么是優(yōu)雅退出呢?所謂的優(yōu)雅退出,其實(shí)就是避免暴力殺死進(jìn)程,讓進(jìn)程在接收到信號之后,自動(dòng)的做一些善后處理,再自己自愿的退出。
Linux Server端的應用程序經(jīng)常會(huì )長(cháng)時(shí)間運行,在運行過(guò)程中,可能申請了很多系統資源,也可能保存了很多狀態(tài),在這些場(chǎng)景下,我們希望進(jìn)程在退出前,可以釋放資源或將當前狀態(tài)dump到磁盤(pán)上或打印一些重要的日志,也就是希望進(jìn)程優(yōu)雅退出(exit gracefully)。
從上面的介紹不難看出,優(yōu)雅退出可以通過(guò)捕獲SIGTERM來(lái)實(shí)現。具體來(lái)講,通常只需要兩步動(dòng)作:
1)注冊SIGTERM信號的處理函數并在處理函數中做一些進(jìn)程退出的準備。信號處理函數的注冊可以通過(guò)signal()或sigaction()來(lái)實(shí)現,其中,推薦使用后者來(lái)實(shí)現信號響應函數的設置。信號處理函數的邏輯越簡(jiǎn)單越好,通常的做法是在該函數中設置一個(gè)bool型的flag變量以表明進(jìn)程收到了SIGTERM信號,準備退出。
2)在主進(jìn)程的main()中,通過(guò)類(lèi)似于while(!bQuit)的邏輯來(lái)檢測那個(gè)flag變量,一旦bQuit在signal handler function中被置為true,則主進(jìn)程退出while()循環(huán),接下來(lái)就是一些釋放資源或dump進(jìn)程當前狀態(tài)或記錄日志的動(dòng)作,完成這些后,主進(jìn)程退出。
這個(gè)在我前面的一篇文章中也介紹過(guò)[golang的httpserver優(yōu)雅重啟](http://helight.info/2018-01-24/984/),里面介紹了一般我們使用的httpserver如何做到優(yōu)雅重啟,這里面也介紹了一些信號的使用,和優(yōu)雅重啟的思路。今天這里我們介紹的是如何優(yōu)雅退出,其實(shí)是優(yōu)雅重啟的一個(gè)簡(jiǎn)化版。
package main import ( "fmt" "os" "os/signal" "syscall" "time" ) func main() { sigs := make(chan os.Signal, 1) // done := make(chan bool, 1) // signal.Notify(sigs) // signal.Notify(sigs, os.Interrupt, os.Kill, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sigs, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT) // go func() { // sig := <-sigs // fmt.Println(sig) // done <- true // }() go func() { for s := range sigs { switch s { case syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT: fmt.Println("got signal and try to exit: ", s) do_exit() case syscall.SIGUSR1: fmt.Println("usr1: ", s) case syscall.SIGUSR2: fmt.Println("usr2: ", s) default: fmt.Println("other: ", s) } } }() fmt.Println("wait for signal") i := 0 for { i++ fmt.Println("times: ", i) time.Sleep(1 * time.Second) } // <- done fmt.Println("got signal and exit") fmt.Println("run done") } func do_exit() { fmt.Println("try do some clear jobs") fmt.Println("run done") os.Exit(0) }
kill -USR1 pid usr1 user defined signal 1 kill -USR2 pid usr2 user defined signal 2 kill -QUIT pid got signal and try to exit: quit try do some clear jobs run done
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站