本文剖析 ANSI <signal.h> 庫並示範其介面用法,進而討論 POSIX 信號處理 API。
信號似硬體中斷,使進程跳出當前控制流執行特定行為,處理完恢復原處繼續。預設某些信號導致進程終止 (如存取非擁有記憶體觸發 SIGSEGV)。調試、模擬、事務系統必須處理此類信號讓進程繼續執行。對策:安裝處理器捕獲信號。
信號為核心傳給進程的整數。進程收到信號可:忽略、讓核心執行預設動作、捕獲 (核心將控制權交給處理常式,執行完恢復)。
signal() 為給定信號註冊處理常式:
typedef void (*handler)(void);
void * signal(int signum, handler);
SIG_IGN (忽略,SIGKILL/SIGSTOP 不可忽略/捕獲/阻塞)、SIG_DFL (預設動作)。raise() 顯式發送給自己。kill() 系統呼叫或 Perl 腳本。#include <csignal>
#include <iostream>
using namespace std;
void term(int sig) {
// 必要清理操作
cout << "handling signal no." << sig << endl;
}
int main() {
signal(SIGTERM, term); // 註冊 SIGTERM 處理器
raise(SIGTERM); // 觸發 term()
}
進程準備執行 SIGx 處理常式時又收到同一信號怎麼辦?
SIG_DFL。問題:兩信號快速產生時,核心跑第一個處理常式,第二個執行預設動作 → 可能終止進程。過去 30 年出現多種信號處理框架,POSIX 信號 API 最成熟可移植。
操作打包在 sigset_t 中的信號集:
sigemptyset:清空集合sigfillset:填入所有可用信號sigaddset:加入信號sigdelset:移除信號sigismember:檢查信號是否在集合中int sigaction(int signum, struct sigaction *act, struct sigaction *prev);
sigaction 結構描述核心處理 signum 的資訊:
struct sigaction {
sighandler_t sa_handler; // 處理函數位址 (帶 int 參數,無回傳),或 SIG_DFL/SIG_IGN
sigset_t sa_mask; // 阻塞信號清單
unsigned long sa_flags; // 阻塞模式
void (*sa_restorer)(void); // 未使用
};
int sigprocmask(int mode, const sigset_t* newmask, sigset_t* oldmask);
SIG_BLOCK:將 newmask 信號加入當前阻塞罩。SIG_UNBLOCK:從阻塞罩移除 newmask 信號。SIG_SETMASK:僅阻塞 newmask 信號。被阻塞信號處於等待狀態,稱「未決信號」,可用 sigpending(sigset_t *pset) 獲取。