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

C語言進程間通信:sigaction 替代 signal 實現可靠信號處理

     編輯:關於C

signal() 是早期 Unix 信號處理接口,語義不一致、不可移植、且存在競態條件(處理函數未就緒前信號到達)。POSIX 標準推薦使用 sigaction():功能更強、語義明確、支持信號屏蔽集、可靠性更高。本文詳細對比兩者,並給出 sigaction 完整父子進程通信代碼。

signal vs sigaction 核心差異

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

關鍵點說明

  1. 信號處理繼承:fork() 後,子進程繼承父進程的信號處理設置(包括 sigaction 註冊的處理函數)。
  2. 原子註冊:sigaction 設置處理函數與屏蔽集是原子的,消除了 signal 的「設置後、生效前」窗口期競態。
  3. 屏蔽集防嵌套:若在處理 SIGALRM 期間不想被 SIGINT 打斷,只需 sigaddset(&act.sa_mask, SIGINT)。

總結

sigaction 是現代 C 程序唯一推薦的信號處理接口:

  1. 結構體配置清晰分離:處理函數、屏蔽集、標誌位。
  2. 支持擴展處理函數獲取 siginfo_t(發送進程 PID、用戶數據、錯誤碼等)。
  3. 可移植、可靠、無競態,滿足高併發、實時系統嚴格要求。

棄用 signal(),擁抱 sigaction(),是編寫專業級 Linux/Unix 系統代碼的基本功。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
特性signal()sigaction()
可移植性差(BSD/System V 語義不同)優(POSIX 標準)
信號屏蔽不支持自定義sa_mask 精確控制處理期間屏蔽信號
處理函數參數僅 int signo可選 siginfo_t*, void* 獲取詳細信息
標誌控制無sa_flags:SA_RESTART, SA_SIGINFO, SA_NOCLDSTOP 等
舊動作獲取返回值第三參數 oldact
競態條件易發生(設置與生效非原子)原子設置,支持屏蔽集防競態