http://en.wikipedia.org/wiki/Category:Unix_signals 1.SIGHUP信號 UNIX中進程組織結構為 session (會話)包含一個前臺進程組及一個或多個后臺進程組,一個進程組包含多個進程。一個session可能會有一個session首進程,而一個session首進程可能會有一個控制終端。一個進程組可能會有一個進程組首進程。進程組首進程的進程ID與該進程組ID相等。這兒是可能會有,在一定情況之下是沒有的。與終端交互的進程是前臺進程,否則便是后臺進程。
SIGHUP會在以下3種情況下被發送給相應的進程:
1、終端關閉時,該信號被發送到session首進程以及作為job提交的進程(即用 & 符號提交的進程)
2、session首進程退出時,該信號被發送到該session中的前臺進程組中的每一個進程
3、若父進程退出導致進程組成為孤兒進程組,且該進程組中有進程處于停止狀態(收到SIGSTOP或SIGTSTP信號),該信號會被發送到該進程組中的每一個進程。
系統對SIGHUP信號的默認處理是終止收到該信號的進程。所以若程序中沒有捕捉該信號,當收到該信號時,進程就會退出。
下面觀察幾種因終端關閉導致進程退出的情況,在這兒進程退出是因為收到了SIGHUP信號。login shell是session首進程。
首先寫一個測試程序,代碼如下:
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() 程序中捕捉SIGHUP信號后打印一條信息,pause()使程序暫停。
編譯后的執行文件為sigtest。
1、命 令:sigtest front > tt.txt
操 作:關閉終端
結 果:tt.txt文件的內容為front : sighup received
原 因: sigtest是前臺進程,終端關閉后,根據上面提到的第1種情況,login shell作為session首進程,會收到SIGHUP信號然后退出。根據第2種情況,sigtest作為前臺進程,會收到login shell發出的SIGHUP信號。
2、命 令:sigtest back > tt.txt &
操 作:關閉終端
結 果:tt.txt文件的內容為 back : sighup received
原 因: sigtest是提交的job,根據上面提到的第1種情況,sigtest會收到SIGHUP信號。
3、命 令:寫一個shell,內容為[sigtest &],然后執行該shell
操 作:關閉終端
結 果:ps -ef | grep sigtest 會看到該進程還在,tt文件為空
原 因: 執行該shell時,sigtest作為job提交,然后該shell退出,致使sigtest變成了孤兒進程,不再是當前session的job了,因此sigtest即不是session首進程也不是job,不會收到SIGHUP。同時孤兒進程屬于后臺進程,因此login shell退出后不會發送SIGHUP給sigtest,因為它只將該信號發送給前臺進程。第3條說過若進程組變成孤兒進程組的時候,若有進程處于停止狀態,也會收到SIGHUP信號,但sigtest沒有處于停止狀態,所以不會收到SIGHUP信號。
4、命 令:nohup sigtest > tt
操 作:關閉終端
結 果:tt文件為空
原 因: nohup可以防止進程收到SIGHUP信號
至此,我們就清楚了何種情況下終端關閉后進程會退出,何種情況下不會退出。
要想終端關閉后進程不退出有以下幾種方法,均為通過shell的方式:
1、編寫shell,內容如下
trap "" SIGHUP #該句的作用是屏蔽SIGHUP信號,trap可以屏蔽很多信號
sigtest
2、nohup sigtest 可以直接在命令行執行,
若想做完該操作后繼續別的操作,可以 nohup sigtest &
3、編寫shell,內容如下
sigtest &
其實任何將進程變為孤兒進程的方式都可以,包括fork后父進程馬上退出。
2.SIGCHLD信號 子進程死后,會發送SIGCHLD信號給父進程。 一個進程在調用exit命令結束自己的生命的時候,其實它并沒有真正的被銷毀,而是留下一個稱為僵尸進程(Zombie)的數據結構(系統調用exit,它的作用是使進程退出,但也僅僅限于將一個正常的進程變成一個僵尸進程,并不能將其完全銷毀)。在Linux進程的狀態中,僵尸進程 是非常特殊的一種,它已經放棄了幾乎所有內存空間,沒有任何可執行代碼,也不能被調度,僅僅在進程列表中保留一個位置,記載該進程的退出狀態等信息供其他進程收集,除此之外,僵尸進程不再占有任何內存空間。它需要它的父進程來為它收尸,如果他的父進程沒安裝SIGCHLD信號處理函數調用wait或waitpid()等待子進程結束,又沒有顯式忽略該信號,那么它就一直保持僵尸狀態,如果這時父進程結束了,那么init進程自動會接手這個子進程,為它收尸,它還是能被清除的。但是如果如果父進程是一個循環,不會結束,那么子進程就會一直保持僵尸狀態,這就是為什么系統中有時會有很多的僵尸進程。 2.SIGTERM信號 kill() 可以發 SIGTERM 過去;kill 命令默認也使用 SIGTERM 信號。 |
$ kill -l 列表中,編號為1 ~ 31的信號為傳統UNIX支持的信號,是不可靠信號(非實時的),編號為32 ~ 63的信號是后來擴充的,稱做可靠信號(實時信號)。不可靠信號和可靠信號的區別在于前者不支持排隊,可能會造成信號丟失,而后者不會。 下面我們對編號小于SIGRTMIN的信號進行討論。 1) SIGHUP 登錄Linux時,系統會分配給登錄用戶一個終端(Session)。在這個終端運行的所有程序,包括前臺進程組和后臺進程組,一般都屬于這個 Session。當用戶退出Linux登錄時,前臺進程組和后臺有對終端輸出的進程將會收到SIGHUP信號。這個信號的默認操作為終止進程,因此前臺進 程組和后臺有終端輸出的進程就會中止。不過可以捕獲這個信號,比如wget能捕獲SIGHUP信號,并忽略它,這樣就算退出了Linux登錄,wget也 能繼續下載。 此外,對于與終端脫離關系的守護進程,這個信號用于通知它重新讀取配置文件。 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD 如果父進程沒有處理這個信號,也沒有等待(wait)子進程,子進程雖然終止,但是還會在內核進程表中占有表項,這時的子進程稱為僵尸進程。這種情 況我們應該避免(父進程或者忽略SIGCHILD信號,或者捕捉它,或者wait它派生的子進程,或者父進程先終止,這時子進程的終止自動由init進程來接管)。 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 在以上列出的信號中,程序不可捕獲、阻塞或忽略的信號有:SIGKILL,SIGSTOP 此外,SIGIO在SVR4是退出,在4.3BSD中是忽略;SIGCONT在進程掛起時是繼續,否則是忽略,不能被阻塞。 |