訊號是 Unix 系統中進程間非同步通訊的基本機制,模擬硬體中斷在軟體層實現。本章涵蓋訊號語義、不可靠/可靠訊號、訊號集、sigaction、setjmp/longjmp、定時器、流量控制等核心內容。
SIGINT(Ctrl+C)、SIGQUIT(Ctrl+\)、SIGCHLD(子進程狀態變化)、SIGALRM(定時器)、SIGKILL/SIGSTOP(不可捕捉/忽略)typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
缺陷:舊版 Unix 執行處理函數前會重置為預設動作,導致短暫窗口期再次收到同一訊號會觸發預設動作(競態條件)。且無法阻塞其他訊號。
核心維護兩個位圖:
進程從核心態返回用戶態前,執行 mask & pending,非零則觸發處理。特性:
longjmp:會遺留 mask 狀態| 函數 | 用途 |
|---|---|
sigaction | 替代 signal,支援 sa_mask 阻塞集合、SA_SIGINFO 獲取詳細資訊、SA_RESTART 自動重啟系統呼叫 |
sigprocmask | 阻塞/解除阻塞/設定訊號集 (SIG_BLOCK/UNBLOCK/SETMASK) |
sigsuspend | 原子性:解除阻塞 + 等待訊號 + 恢復阻塞,解決 pause 競態 |
sigpending | 查看 pending 集合 (需先阻塞所有訊號才準確) |
kill | 發送訊號給進程/進程組/全系統 |
alarm/setitimer | 定時發送 SIGALRM/SIGVTALRM/SIGPROF |
_r 後綴版本 (如 strerror_r) 則原版不可重入使用 SIGALRM 定期填充 token,pause/sigsuspend 等待 token 可用:
static volatile int token = 0;
void alarm_handler(int s) { alarm(1); if (token < MAX) token++; }
while (token <= 0) { sigsuspend(&mask); } // 原子等待
token--; // 消費 token 進行讀寫
sigsetjmp(env, 1) 儲存訊號遮罩,siglongjmp 恢復。限制:只能跳回被中斷的函數,否則段錯誤。
呼叫 system 前必須:阻塞 SIGCHLD、忽略 SIGINT/SIGQUIT,避免干擾 shell 子進程。
sigqueue + sa_sigaction)掌握訊號機制是編寫健壯 Unix 系統程式、守護進程、高併發伺服器的基石。