| 特性 | signal() | sigaction() |
| 可移植性 | 差(BSD/System V 語義不同) | 優(POSIX 標準) |
| 信號屏蔽 | 不支持自定義 | sa_mask 精確控制處理期間屏蔽信號 |
| 處理函數參數 | 僅 int signo | 可選 siginfo_t*, void* 獲取詳細信息 |
| 標誌控制 | 無 | sa_flags:SA_RESTART, SA_SIGINFO, SA_NOCLDSTOP 等 |
| 舊動作獲取 | 返回值 | 第三參數 oldact |
| 競態條件 | 易發生(設置與生效非原子) | 原子設置,支持屏蔽集防競態 |
sigaction 結構體詳解
struct sigaction {
void (*sa_handler)(int); // 傳統處理函數
void (*sa_sigaction)(int, siginfo_t*, void*); // 擴展處理函數
sigset_t sa_mask; // 處理期間額外屏蔽的信號集
int sa_flags; // 行為標誌
void (*sa_restorer)(void); // 已廢棄,忽略
};
sa_handler 與 sa_sigaction 二擇一,由 SA_SIGINFO 標誌決定。
sa_mask:調用處理函數前,自動將該集合內信號加入進程屏蔽集,處理完恢復,防止嵌套中斷。
sa_flags 常用值:SA_RESTART(系統調用被中斷後自動重啟)、SA_SIGINFO(啟用擴展處理函數)、SA_NOCLDSTOP(子進程停止不產生 SIGCHLD)。
完整代碼:父進程發送 SIGALRM,子進程 sigaction 處理
#include
#include
#include
#include
void sig_receive(int signo) {
printf("Received signal: %d\n", signo);
printf("Signal processing in PID: %d\n", getpid());
}
int main() {
pid_t pid, pid_res;
int stat_value;
struct sigaction act;
// 1. 配置 sigaction
act.sa_handler = sig_receive; // 設置處理函數
sigemptyset(&act.sa_mask); // 屏蔽集為空
act.sa_flags = 0; // 無特殊標誌
// 2. 註冊 SIGALRM
if (sigaction(SIGALRM, &act, NULL) == -1) {
perror("sigaction");
return 1;
}
// 3. 創建子進程
pid = fork();
if (pid < 0) {
perror("fork");
return 1;
}
if (pid > 0) { // 父進程:發送信號
printf("PID: %d -> Father sends signal\n", getpid());
kill(pid, SIGALRM);
} else { // 子進程:接收信號(已繼承父進程的信號處理設置)
printf("PID: %d -> Son waits for signal\n", getpid());
// 子進程可在此處 pause() 等待信號,或繼續執行
}
// 4. 父進程等待子進程
pid_res = wait(&stat_value);
if (pid_res > 0) {
printf("Son process finished: PID = %d\n", pid_res);
}
return 0;
}
運行結果
PID: 4468 -> Father sends signal
Received signal: 14
Signal processing in PID: 4469
PID: 4469 -> Son waits for signal
Son process finished: PID = 4469
關鍵點說明
- 信號處理繼承:
fork() 後,子進程繼承父進程的信號處理設置(包括 sigaction 註冊的處理函數)。
- 原子註冊:
sigaction 設置處理函數與屏蔽集是原子的,消除了 signal 的「設置後、生效前」窗口期競態。
- 屏蔽集防嵌套:若在處理 SIGALRM 期間不想被 SIGINT 打斷,只需
sigaddset(&act.sa_mask, SIGINT)。
總結
sigaction 是現代 C 程序唯一推薦的信號處理接口:
- 結構體配置清晰分離:處理函數、屏蔽集、標誌位。
- 支持擴展處理函數獲取
siginfo_t(發送進程 PID、用戶數據、錯誤碼等)。
- 可移植、可靠、無競態,滿足高併發、實時系統嚴格要求。
棄用 signal(),擁抱 sigaction(),是編寫專業級 Linux/Unix 系統代碼的基本功。
- 上一篇文章: Qt Widgets 桌面應用發布部署:windeployqt 一鍵自動化
- 下一篇文章: Qt5 獲取本機網絡信息:IP、主機名、MAC、子網掩碼、廣播地址
Copyright ©
程式碼之家 All Rights Reserved