首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

APUE 訊號機制完整指南:從基本概念到可靠訊號與實戰應用

     編輯:關於C語言

Unix 環境高級編程(APUE)第 10 章:訊號深度解析

訊號是 Unix 系統中進程間非同步通訊的基本機制,模擬硬體中斷在軟體層實現。本章涵蓋訊號語義、不可靠/可靠訊號、訊號集、sigaction、setjmp/longjmp、定時器、流量控制等核心內容。

1. 訊號基礎與分類

  • 標準訊號 (1-31):SIGINT(Ctrl+C)、SIGQUIT(Ctrl+\)、SIGCHLD(子進程狀態變化)、SIGALRM(定時器)、SIGKILL/SIGSTOP(不可捕捉/忽略)
  • 即時訊號 (34-64):支援排隊、不丟失、優先級語義
  • 五種預設動作:終止、終止+Core Dump、忽略、停止、繼續

2. signal() 與其缺陷

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

缺陷:舊版 Unix 執行處理函數前會重置為預設動作,導致短暫窗口期再次收到同一訊號會觸發預設動作(競態條件)。且無法阻塞其他訊號。

3. 可靠訊號機制:mask 與 pending 位圖

核心維護兩個位圖:

  • mask:1=允許遞送,0=阻塞
  • pending:1=已送達待處理,0=無

進程從核心態返回用戶態前,執行 mask & pending,非零則觸發處理。特性:

  1. 阻塞訊號:對應 mask 位設 0
  2. 遞送延遲:最長 ~10ms (等待排程)
  3. 標準訊號不排隊:pending 為位圖,多次送達僅保留一次
  4. 處理函數嵌套:新訊號到達可中斷當前處理函數
  5. 不可在處理函數中 longjmp:會遺留 mask 狀態

4. 關鍵系統呼叫

函數用途
sigaction替代 signal,支援 sa_mask 阻塞集合、SA_SIGINFO 獲取詳細資訊、SA_RESTART 自動重啟系統呼叫
sigprocmask阻塞/解除阻塞/設定訊號集 (SIG_BLOCK/UNBLOCK/SETMASK)
sigsuspend原子性:解除阻塞 + 等待訊號 + 恢復阻塞,解決 pause 競態
sigpending查看 pending 集合 (需先阻塞所有訊號才準確)
kill發送訊號給進程/進程組/全系統
alarm/setitimer定時發送 SIGALRM/SIGVTALRM/SIGPROF

5. 可重入函數與訊號處理安全

  • 所有系統呼叫均為可重入
  • 標準庫函數若有 _r 後綴版本 (如 strerror_r) 則原版不可重入
  • 處理函數中僅使用可重入函數、單純計算、volatile 旗標變數

6. 實戰範例:流量控制 (Token Bucket)

使用 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 進行讀寫

7. setjmp / sigsetjmp / longjmp

sigsetjmp(env, 1) 儲存訊號遮罩,siglongjmp 恢復。限制:只能跳回被中斷的函數,否則段錯誤。

8. system() 與訊號

呼叫 system 前必須:阻塞 SIGCHLD、忽略 SIGINT/SIGQUIT,避免干擾 shell 子進程。

9. 即時訊號優勢

  • 鏈結串列實現,支援排隊不丟失
  • 先到先服務,可傳遞資料 (sigqueue + sa_sigaction)
  • 優先級語義:高優先級先遞送

掌握訊號機制是編寫健壯 Unix 系統程式、守護進程、高併發伺服器的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved