常見的信號(common signals)
在數十個已定義的信號中,有少數幾個不斷出現,知道每個的意思能把許多令人困惑的行為變得一目了然。把它們想成一小套「輕推」的詞彙,每個都有約定俗成的意義,以及一個核心在你未另行安排時會採取的預設動作。
以下是你最常遇到的幾個。SIGINT(中斷)是 Ctrl-C 送出的;來自鍵盤、客氣的「請停下」——預設:終止。SIGTERM(終止)是標準、可攔截的「請乾淨地關閉」,是 kill 預設送出的、也是 init 系統用來停止服務的——預設:終止,但程式可以攔截它以先把檔案寫出。SIGKILL 是無法阻擋的那一個:它不能被攔截、阻擋或忽略,核心會立即摧毀該行程——只在 SIGTERM 被忽略時才用它,因為行程得不到任何清理的機會。SIGSEGV(區段違規)是核心在你程式碰觸不該碰的記憶體時送出的(解參考一個空指標或野指標)——預設:終止,通常伴隨核心傾印。SIGCHLD 在某個子行程停止或死亡時送給父行程,讓父行程知道該 wait() 並回收它——預設:忽略。SIGPIPE 在你寫入一條讀取端已不在的管線或通訊端時送出——預設:終止。
重要的分組:SIGINT 與 SIGTERM 是你可以攔截並優雅處理的請求;SIGKILL(與 SIGSTOP)是任何程式都無法蓋過的那兩個,是系統最終的權威。SIGSEGV 與 SIGPIPE 通常是錯誤或對端消失的症狀,而非你刻意去送的東西。記熟這份短名單是系統程式設計中槓桿最高的事情之一——它解釋了為什麼 kill -9 永遠有效、為什麼 Ctrl-C 有時停不掉一個程式(它裝了處理常式)、以及為什麼當機報告寫著「signal 11」。
$ kill 1234 # 送 SIGTERM——請行程 1234 關閉 $ kill -9 1234 # 送 SIGKILL——直接摧毀它,不做清理 當機是 segfault?是核心送了 SIGSEGV(信號 11),因為你解參考了一個壞指標。
TERM 是請求、KILL 是強制、SEGV 是當機、CHLD 是「你的孩子做完了」、PIPE 是「讀取方走了」。
SIGKILL 與 SIGSTOP 是僅有的兩個行程永遠無法攔截、阻擋或忽略的信號——這是刻意設計,好讓系統永遠保有停止失控行程的手段。其餘的一切都可以被處理(或處理不當)。