Linux系統(tǒng)中的信號類型以及Go中的信號發(fā)送和處理

本篇內(nèi)容介紹了“Linux系統(tǒng)中的信號類型以及Go中的信號發(fā)送和處理”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

本篇內(nèi)容介紹了“Linux系統(tǒng)中的信號類型以及Go中的信號發(fā)送和處理”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

Linux系統(tǒng)中的信號類型
各操作系統(tǒng)的信號定義或許有些不同。下面列出了POSIX中定義的信號。
在linux中使用34-64信號用作實(shí)時(shí)系統(tǒng)中。
命令 man 7 signal 提供了官方的信號介紹。也可以是用kill -l來快速查看
列表中,編號為1 ~ 31的信號為傳統(tǒng)UNIX支持的信號,是不可靠信號(非實(shí)時(shí)的),編號為32 ~ 63的信號是后來擴(kuò)充的,稱做可靠信號(實(shí)時(shí)信號)。不可靠信號和可靠信號的區(qū)別在于前者不支持排隊(duì),可能會(huì)造成信號丟失,而后者不會(huì)。
Linux支持的標(biāo)準(zhǔn)信號有以下一些,一個(gè)信號有多個(gè)值的是因?yàn)椴煌軜?gòu)使用的值不一樣,比如x86, ia64,ppc, s390, 有3個(gè)值的,第一個(gè)值是slpha和sparc,中間的值是 ix86,
ia64, ppc, s390, arm和sh, 最后一個(gè)值是對mips的,連字符-表示這個(gè)架構(gòu)是缺這個(gè)信號支持的,
第1列為信號名;
第2列為對應(yīng)的信號值,需要注意的是,有些信號名對應(yīng)著3個(gè)信號值,這是因?yàn)檫@些信號值與平臺相關(guān),將man手冊中對3個(gè)信號值的說明摘出如下,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)收到信號后的動(dòng)作,Term表明默認(rèn)動(dòng)作為終止進(jìn)程,Ign表明默認(rèn)動(dòng)作為忽略該信號,Core表明默認(rèn)動(dòng)作為終止進(jìn)程同時(shí)輸出core dump,Stop表明默認(rèn)動(dòng)作為停止進(jìn)程。

成都創(chuàng)新互聯(lián)公司主營沂水網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶APP開發(fā),沂水h5成都微信小程序搭建,沂水網(wǎng)站營銷推廣歡迎沂水等地區(qū)企業(yè)咨詢

第4列為對信號作用的注釋性說明。

標(biāo)準(zhǔn)信號-POSIX.1-1990定義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信號是不能被捕獲,阻塞和忽略的。

標(biāo)準(zhǔn)信號-SUSv2 and POSIX.1-2001定義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架構(gòu))的默認(rèn)操作就是終止進(jìn)程(但是不產(chǎn)生coredump)

在一些unix系統(tǒng)中SIGXCPU和SIGXFSZ信號是用來終止進(jìn)程的,也是不產(chǎn)生coredunp,從Linux 2.4開始這些信號會(huì)產(chǎn)生coredump了。

標(biāo)準(zhǔn)信號-其它信號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沒有在POSIX.1-2001中定義, 但是在大多數(shù)Unix戲中是沒有的,他的默認(rèn)處理方式是coredump并且終止進(jìn)程。
SIGPWR(沒有在POSIX.1-2001中定義)他的默認(rèn)處理方式是忽略。

SIGIO(沒有在POSIX.1-2001中定義)在一些Unix系統(tǒng)中的處理方式也是忽略。

kill pid的作用是向進(jìn)程號為pid的進(jìn)程發(fā)送SIGTERM(這是kill默認(rèn)發(fā)送的信號),該信號是一個(gè)結(jié)束進(jìn)程的信號且可以被應(yīng)用程序捕獲。若應(yīng)用程序沒有捕獲并響應(yīng)該信號的邏輯代碼,則該信號的默認(rèn)動(dòng)作是kill掉進(jìn)程。這是終止指定進(jìn)程的推薦做法。

kill -9 pid則是向進(jìn)程號為pid的進(jìn)程發(fā)送SIGKILL(該信號的編號為9),從本文上面的說明可知,SIGKILL既不能被應(yīng)用程序捕獲,也不能被阻塞或忽略,其動(dòng)作是立即結(jié)束指定進(jìn)程。通俗地說,應(yīng)用程序根本無法“感知”SIGKILL信號,它在完全無準(zhǔn)備的情況下,就被收到SIGKILL信號的操作系統(tǒng)給干掉了,顯然,在這種“暴力”情況下,應(yīng)用程序完全沒有釋放當(dāng)前占用資源的機(jī)會(huì)。事實(shí)上,SIGKILL信號是直接發(fā)給init進(jìn)程的,它收到該信號后,負(fù)責(zé)終止pid指定的進(jìn)程。在某些情況下(如進(jìn)程已經(jīng)hang死,無法響應(yīng)正常信號),就可以使用kill -9來結(jié)束進(jìn)程。

若通過kill結(jié)束的進(jìn)程是一個(gè)創(chuàng)建過子進(jìn)程的父進(jìn)程,則其子進(jìn)程就會(huì)成為孤兒進(jìn)程(Orphan Process),這種情況下,子進(jìn)程的退出狀態(tài)就不能再被應(yīng)用進(jìn)程捕獲(因?yàn)樽鳛楦高M(jìn)程的應(yīng)用程序已經(jīng)不存在了),不過應(yīng)該不會(huì)對整個(gè)linux系統(tǒng)產(chǎn)生什么不利影響。

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

有時(shí)候我們想在Go程序中處理Signal信號,比如收到 SIGTERM 信號后優(yōu)雅的關(guān)閉程序(參看下一節(jié)的應(yīng)用)。Go信號通知機(jī)制可以通過往一個(gè)channel中發(fā)送 os.Signal 實(shí)現(xiàn)。首先我們創(chuàng)建一個(gè)os.Signal channel,然后使用 signal.Notify 注冊要接收的信號。

package mainimport ( "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")}如何實(shí)現(xiàn)進(jìn)程的優(yōu)雅退出
首先什么是優(yōu)雅退出呢?所謂的優(yōu)雅退出,其實(shí)就是避免暴力殺死進(jìn)程,讓進(jìn)程在接收到信號之后,自動(dòng)的做一些善后處理,再自己自愿的退出。
Linux Server端的應(yīng)用程序經(jīng)常會(huì)長時(shí)間運(yùn)行,在運(yùn)行過程中,可能申請了很多系統(tǒng)資源,也可能保存了很多狀態(tài),在這些場景下,我們希望進(jìn)程在退出前,可以釋放資源或?qū)?dāng)前狀態(tài)dump到磁盤上或打印一些重要的日志,也就是希望進(jìn)程優(yōu)雅退出(exit gracefully)。
從上面的介紹不難看出,優(yōu)雅退出可以通過捕獲SIGTERM來實(shí)現(xiàn)。具體來講,通常只需要兩步動(dòng)作:
1)注冊SIGTERM信號的處理函數(shù)并在處理函數(shù)中做一些進(jìn)程退出的準(zhǔn)備。信號處理函數(shù)的注冊可以通過signal()或sigaction()來實(shí)現(xiàn),其中,推薦使用后者來實(shí)現(xiàn)信號響應(yīng)函數(shù)的設(shè)置。信號處理函數(shù)的邏輯越簡單越好,通常的做法是在該函數(shù)中設(shè)置一個(gè)bool型的flag變量以表明進(jìn)程收到了SIGTERM信號,準(zhǔn)備退出。
2)在主進(jìn)程的main()中,通過類似于while(!bQuit)的邏輯來檢測那個(gè)flag變量,一旦bQuit在signal handler function中被置為true,則主進(jìn)程退出while()循環(huán),接下來就是一些釋放資源或dump進(jìn)程當(dāng)前狀態(tài)或記錄日志的動(dòng)作,完成這些后,主進(jìn)程退出。

這個(gè)在我前面的一篇文章中也介紹過[golang的httpserver優(yōu)雅重啟](http://helight.info/2018-01-24/984/),里面介紹了一般我們使用的httpserver如何做到優(yōu)雅重啟,這里面也介紹了一些信號的使用,和優(yōu)雅重啟的思路。今天這里我們介紹的是如何優(yōu)雅退出,其實(shí)是優(yōu)雅重啟的一個(gè)簡化版。

package mainimport ( "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 1kill -USR2 pid usr2 user defined signal 2kill  -QUIT pid got signal and try to exit: quittry do some clear jobsrun done

名稱欄目:Linux系統(tǒng)中的信號類型以及Go中的信號發(fā)送和處理
文章網(wǎng)址:http://bm7419.com/article16/dg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名、軟件開發(fā)、網(wǎng)站維護(hù)、微信公眾號電子商務(wù)、移動(dòng)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化