Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 訊號機制深度解析:32 號以下不可靠 vs 33-64 號可靠訊號、sigaction 實戰與核心處理流程

編輯:Linux 教學

訊號分類:不可靠 vs 可靠 (實時)

類別編號範圍別名排隊支援丟失可能典型用途
不可靠訊號1~31非實時訊號❌ 不支援排隊✅ 同一訊號多次發送,進程僅收到一次終端控制 (SIGINT, SIGTSTP)、錯誤通知 (SIGSEGV, SIGFPE)、進程管理 (SIGCHLD, SIGKILL)
可靠訊號32~64實時訊號 (RT)✅ 支援排隊❌ 發多少次收多少次使用者自定義通知、高併發事件傳遞、POSIX 計時器到期

終端查看完整列表:kill -l

常見不可靠訊號速查表 (節錄)

編號名稱預設動作典型來源
1SIGHUP終止終端斷開、nohup 忽略
2SIGINT終止Ctrl+C
3SIGQUIT核心轉儲Ctrl+\
9SIGKILL終止 (不可捕捉/阻塞/忽略)kill -9
11SIGSEGV核心轉儲非法記憶體存取
13SIGPIPE終止管道無讀端寫入
14SIGALRM終止alarm(), setitimer()
15SIGTERM終止kill 預設、系統關機
17SIGCHLD忽略子進程結束
19SIGSTOP停止 (不可捕捉/阻塞/忽略)kill -STOP
20SIGTSTP停止Ctrl+Z

訊號產生來源

  • 硬體:使用者輸入 (Ctrl+C → SIGINT)、CPU 異常 (除零 → SIGFPE、非法存取 → SIGSEGV)。
  • 軟體 (系統呼叫):kill(), raise(), sigqueue() (可攜帶資料), alarm(), setitimer(), abort(), pthread_kill()。

訊號安裝:signal() vs sigaction()

// 過時、不可攜帶資料、不可靠訊號語意不一
void (*signal(int signum, void (*handler)(int)))(int);

// 標準、支援資料傳遞、可控制阻塞集合、旗標豐富
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

sigaction 結構體關鍵欄位

struct sigaction {
    void     (*sa_handler)(int);           // 傳統處理函式
    void     (*sa_sigaction)(int, siginfo_t*, void*); // SA_SIGINFO 時使用,可取得 siginfo_t
    sigset_t   sa_mask;                    // 處理函式執行期間額外阻塞的訊號集
    int        sa_flags;                   // 行為旗標組合
    void     (*sa_restorer)(void);         // 內部用,忽略
};

sa_flags 常用旗標

  • SA_RESTART:被訊號中斷的系統呼叫自動重啟 (避免 EINTR)。
  • SA_NOCLDSTOP:子進程停止/繼續不產生 SIGCHLD。
  • SA_NOCLDWAIT:子進程結束不產生 SIGCHLD,且不成為殭屍進程。
  • SA_SIGINFO:啟用 sa_sigaction,可取得 siginfo_t (發送者 PID/UID、訊號值、地址等)。
  • SA_NODEFER:處理期間不自動阻塞自身訊號 (預設會阻塞)。
  • SA_RESETHAND:處理一次後恢復預設動作。

訊號集操作函式

sigemptyset(set)   // 清空
sigfillset(set)    // 填滿所有訊號
sigaddset(set, sig)    // 加入
sigdelset(set, sig)    // 刪除
sigismember(set, sig)  // 判斷

阻塞/解除阻塞/待處理訊號查詢

sigprocmask(SIG_BLOCK,   &set, &old)  // 加入阻塞集
sigprocmask(SIG_UNBLOCK, &set, &old)  // 移除阻塞集
sigprocmask(SIG_SETMASK, &set, &old)  // 設定阻塞集
sigpending(&set)                      // 取得已送達但被阻塞的訊號集
sigsuspend(&mask)                     // 原子性:替換阻塞集並暫停,收到訊號恢復

核心處理流程與時機

  1. 訊號送達 → 掛入進程 task_struct->pending (不可靠訊號去重,可靠訊號入隊)。
  2. 進程從核心態返回使用者態時 (系統呼叫返回、中斷返回、排程器切換),檢查 pending & ~blocked。
  3. 若有未阻塞待處理訊號:
    a. 依 sa_mask 設定暫時阻塞集。
    b. 切換到使用者棧,呼叫處理函式 (sa_handler 或 sa_sigaction)。
    c. 返回核心態,恢復原阻塞集,移除該訊號 pending 位。
    d. 繼續執行使用者代碼。
關鍵點:訊號處理只發生在使用者態,核心態不處理訊號。sigprocmask 修改阻塞集後,下一次核心→使用者態轉換才生效。

實戰範例:使用 sigaction + sigqueue 傳遞資料

// 接收端
void handler(int sig, siginfo_t *info, void *ctx) {
    printf("Received value: %d from PID %d\n", info->si_value.sival_int, info->si_pid);
}
struct sigaction act = {0};
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO;
sigemptyset(&act.sa_mask);
sigaction(SIGRTMIN, &act, NULL);

// 發送端
union sigval val;
val.sival_int = 12345;
sigqueue(target_pid, SIGRTMIN, val);
Copyright © Windows教程網 All Rights Reserved