Linux中的信號

2020-07-16 10:04:48
在 Linux 中,理解信號的概念是非常重要的。這是因為,信號被用於通過 Linux 命令列所做的一些常見活動中。例如,每當你按 Ctrl+C 組合鍵來從命令列終結一個命令的執行,你就使用了信號。每當你使用如下命令來結束一個進程時,你就使用了信號:

kill -9 [PID]

所以,至少知道信號的基本原理是非常有用的。

Linux中的信號

在 Linux 系統(以及其他類 Unix 作業系統)中,信號被用於進程間的通訊。信號是一個傳送到某個進程或同一進程中的特定執行緒的非同步通知,用於通知發生的一個事件。從 1970 年貝爾實驗室的 Unix 面世便有了信號的概念,而現在它已經被定義在了 POSIX 標準中。

對於在 Linux 環境進行程式設計的使用者或系統管理員來說,較好地理解信號的概念和機制是很重要的,在某些情況下可以幫助我們更高效地編寫程式。對於一個程式來說,如果每條指令都執行正常的話,它會連續地執行。但如果在程式執行時,出現了一個錯誤或任何異常,核心就可以使用信號來通知相應的進程。

信號同樣被用於通訊、同步進程和簡化進程間通訊,在 Linux 中,信號在處理異常和中斷方面,扮演了極其重要的角色。信號巳經在沒有任何較大修改的情況下被使用了將近 30 年。

當一個事件發生時,會產生一個信號,然後核心會將事件傳遞到接收的進程。有時,進程可以傳送一個信號到其他進程。除了進程到進程的信號外,還有很多種情況,核心會產生一個信號,比如檔案大小達到限額、一個 I/O 裝置就緒或使用者傳送了一個類似於 Ctrl+C 或 Ctrl+Z 的終端中斷等。

執行在使用者模式下的進程會接收信號。如果接收的進程正執行在核心模式,那麼信號的執行只有在該進程返回到使用者模式時才會開始。

傳送到非執行進程的信號一定是由核心儲存,直到進程重新執行為止。休眠的進程可以是可中斷的,也可以是不可中斷的。如果一個在可中斷休眠狀態的進程(例如,等待終端輸入的進程)收到了一個信號,那麼核心會喚醒這個進程來處理信號。如果一個在不可中斷休眠狀態的進程收到了一個信號,那麼核心會拖延此信號,直到該事件完成為止。

當進程收到一個信號時,可能會發生以下 3 種情況:
  • 進程可能會忽略此信號。有些信號不能被忽略,而有些沒有預設行為的信號,預設會被忽略。
  • 進程可能會捕獲此信號,並執行一個被稱為信號處理器的特殊函數。
  • 進程可能會執行信號的預設行為。例如,信號 15(SIGTERM) 的預設行為是結束進程。

當一個進程執行信號處理時,如果還有其他信號到達,那麼新的信號會被阻斷直到處理器返冋為止。

信號的名稱和值

每個信號都有以SIG開頭的名稱,並定義為唯一的正整數。在 Shell 命令列提示符 下,輸入kill -l命令,將顯示所有信號的信號值和相應的信號名,類似如下所示:
[c.biancheng.net]$ kill -l
1) SIGHUP        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
16) SIGSTKFLT    17) SIGCHLD        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       34) SIGRTMIN       35) SIGRTMIN+1     36) SIGRTMIN+2    37) SIGRTMIN+3
38) SIGRTMIN+4   39) SIGRTMIN+5     40) SIGRTMIN+6     41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9   44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12   47) SIGRTMIN+13
48) SIGRTMIN+14  49) SIGRTMIN+15    50) SIGRTMAX-14    51) SIGRTMAX-13   52) SIGRTMAX-12
53) SIGRTMAX-11  54) SIGRTMAX-10    55) SIGRTMAX-9     56) SIGRTMAX-8    57) SIGRTMAX-7
58) SIGRTMAX-6   59) SIGRTMAX-5     60) SIGRTMAX-4     61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1   64) SIGRTMAX

信號值被定義在檔案 /usr/include/bits/signum.h 中,其原始檔是 /usr/src/linux/kernel/signal.c。

在 Linux 下,可以檢視 signal(7) 手冊頁來查閱信號名列表、信號值、預設的行為和它們是否可以被捕獲。其命令如下所示:

man 7 signal

下標所列出的信號是 POSIX 標準的一部分,它們通常被縮寫成不帶SIG字首,例如,SIGHUP 通常被簡單地稱為 HUP。

信 號 預設行為 描 述 信號值
SIGABRT 生成 core 檔案然後終止進程 這個信號告訴進程終止操作。ABRT 通常由進程本身傳送,即當進程呼叫 abort() 函數發出一個非正常終止信號時 6
SIGALRM 終止 警告時鐘 14
SIGBUS 生成 core 檔案然後終止進程 當進程引起一個匯流排錯誤時,BUS 信號將被傳送到進程。例如,存取了一部分未定義的記憶體物件 10
SIGCHLD 忽略 當了進程結束、被中斷或是在被中斷之後重新恢復時,CHLD 信號會被傳送到進程 20
SIGCONT 繼續進程 CONT 信號指不作業系統重新開始先前被 STOP 或 TSTP 暫停的進程 19
SIGFPE 生成 core 檔案然後終止進程 當一個進程執行一個錯誤的算術運算時,FPE 信號會被傳送到進程 8
SIGHUP 終止 當進程的控制終端關閉時,HUP 信號會被傳送到進程 1
SIGILL 生成 core 檔案然後終止進程 當一個進程嘗試執行一個非法指令時,ILL 信號會被傳送到進程 4
SIGINT 終止 當使用者想要中斷進程時,INT 信號被進程的控制終端傳送到進程 2
SIGKILL 終止 傳送到進程的 KILL 信號會使進程立即終止。KILL 信號不能被捕獲或忽略 9
SIGPIPE 終止 當一個進程嘗試向一個沒有連線到其他目標的管道寫入時,PIPE 信號會被傳送到進程 13
SIGQUIT 終止 當使用者要求進程執行 core dump 時,QUIT 信號由進程的控制終端傳送到進程 3
SIGSEGV 生成 core 檔案然後終止進程 當進程生成了一個無效的記憶體參照時,SEGV 信號會被傳送到進程 11
SIGSTOP 停止進程 STOP 信號指示作業系統停止進程的執行 17
SIGTERM 終止 傳送到進程的 TERM 信號用於要求進程終止 15
SIGTSTP 停止進程 TSTP 信號由進程的控制終端傳送到進程來要求它立即終止 18
SIGTTIN 停止進程 後台進程嘗試讀取時,TTIN 信號會被傳送到進程 21
SIGTTOU 停止進程 後台進程嘗試輸出時,TTOU 信號會被傳送到進程 22
SIGUSR1 終止 傳送到進程的 USR1 信號用於指示使用者定義的條件 30
SIGUSR2 終止 同上 31
SIGPOLL 終止 當一個非同步輸入/輸出時間事件發生時,POLL  信號會被傳送到進程 23
SIGPROF 終止 當仿形計時器過期時,PROF 信號會被傳送到進程 27
SIGSYS 生成 core 檔案然後終止進程 發生有錯的系統呼叫時,SYS 信號會被傳送到進程 12
SIGTRAP 生成 core 檔案然後終止進程 追蹤捕獲/斷點捕獲時,會產生 TRAP 信號。 5
SIGURG 忽略 當侖一個 socket 有緊急的或是帶外資料可被讀取時,URG 信號會被傳送到進程 16
SIGVTALRM 終止 當進程使用的虛擬計時器過期時,VTALRM 信號會被傳送到進程 26
SIGXCPU 終止 當進程使用的 CPU 時間超出限制時,XCPU 信號會被傳送到進程 24
SIGXFSZ 生成 core 檔案然後終止進程 當檔案大小超過限制時,會產生 XFSZ 信號 25