行程間通訊

用 kill 送出信號(sending a signal with kill)

信號不只來自核心或鍵盤——一個行程可以刻意送一個信號給另一個。做這件事的工具有個不幸嚇人的名字:kill。儘管叫這名字,kill 其實只是「送出信號」,而且大多數信號不會殺死任何東西。這名字是個歷史意外,源自當年預設信號會終止目標的時代。

在命令列上,kill 1234 送 SIGTERM 給 PID 為 1234 的行程(客氣地請它關閉)。kill -9 1234 或 kill -KILL 1234 送 SIGKILL(無法阻擋的摧毀)。kill -SIGUSR1 1234 送一個使用者自訂信號。還有 kill -0 1234,它完全不送信號,只檢查你是否有權對該行程送信號、以及它是否存在——一個方便的「它還活著嗎?」探測。在 C 裡底層呼叫是 kill(pid_t pid, int sig);行程可用 raise(sig) 對自己送信號。特殊的 pid 值能做更多:kill(-pgid, sig) 對整個行程群組送信號,這正是 Ctrl-C 一次觸及管線中每個行程的方式。

有一條權限規則:你通常只能對自己擁有的行程(同一使用者)送信號,若你是 root 則任何行程都行——否則 kill() 會以 EPERM 失敗。誠實的說法:送信號是個粗鈍的工具。它告訴目標「這個狀況發生了」,但你無法附帶資料、無法確定目標處理了它(它可能忽略或阻擋了該信號),也無法輕易得知它是否反應完畢。要做豐富、可靠的通訊,信號是錯的工具——改用管線、通訊端或訊息佇列。信號是用來控制與通知的:停止、重新載入、關閉、「你的子行程死了」。

$ kill -TERM 4242 # 請 PID 4242 結束 $ kill -0 4242 && echo alive || echo gone # 不送信號只探測 在 C 裡:kill(child_pid, SIGUSR1); /* 輕推一個已知的子行程 */

kill 是「送出信號」,不一定是「摧毀」。-9 那種(SIGKILL)才是真正無法被拒絕的那一個。

送信號不會等待或確認對方的反應——kill() 在信號排入佇列後就立刻返回,不是在目標處理完之後。若你需要確認回應,你需要真正的雙向 IPC,而不是信號。

又稱
kill()raise()kill command送出信號