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

C語言進程間通信實戰:使用 sigaction 實現可靠信號處理(下)

     編輯:關於C語言

C語言進程間通信實戰:使用 sigaction 實現可靠信號處理(下)

承接上文,signal() 函數存在語義不一致、無法阻塞信號等缺陷。本篇介紹 POSIX 標準的 sigaction(),它提供了更健壯、可移植的信號處理配置機制。

sigaction 函數原型

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
  • signum:要配置的信號編號(如 SIGALRM、SIGUSR1)。
  • act:新的信號處理配置(struct sigaction*)。
  • oldact:輸出參數,保存舊的配置,不需時可為 NULL。
  • 返回值:成功返回 0,失敗返回 -1 並設置 errno。

sigaction 結構體詳解

struct sigaction {
    void (*sa_handler)(int);           // 普通信號處理函數
    sigset_t sa_mask;                  // 信號屏蔽集,處理函數執行期間自動阻塞的信號
    int sa_flags;                      // 標誌位,控制行為(如 SA_RESTART, SA_SIGINFO)
    void (*sa_sigaction)(int, siginfo_t *, void *); // 擴展處理函數(SA_SIGINFO 時使用)
};

關鍵優勢:sa_mask 允許指定在信號處理函數執行期間臨時阻塞的信號集,避免嵌套中斷;sa_flags 提供豐富行為控制(如重啟被中斷的系統調用)。

完整代碼示例:父進程發送 SIGALRM,子進程捕獲處理

#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;
    int stat_value;
    struct sigaction act = {0};

    // 1. 配置信號處理函數
    act.sa_handler = sig_receive;
    // 2. 設置信號屏蔽集為空(處理期間不阻塞額外信號)
    sigemptyset(&act.sa_mask);
    // 3. 設置標誌位(0 表示默認行為)
    act.sa_flags = 0;

    // 4. 註冊 SIGALRM 的處理動作
    if (sigaction(SIGALRM, &act, NULL) == -1) {
        perror("sigaction failed");
        return 1;
    }

    // 5. 創建子進程
    pid = fork();
    if (pid > 0) {                    // 父進程
        printf("PID: %d -> Father Process send signal\n", getpid());
        kill(pid, SIGALRM);           // 發送信號給子進程
    } else if (pid == 0) {            // 子進程
        printf("PID: %d -> Son Process receive signal\n", getpid());
        // 子進程這裡可執行其他任務,信號到達時會自動調用 sig_receive
    } else {
        perror("fork failed");
        return 1;
    }

    // 父進程等待子進程結束
    pid_t pid_res = wait(&stat_value);
    if (pid_res > 0) {
        printf("Son process finished: PID = %d\n", pid_res);
    }
    return 0;
}

運行結果

PID: 4468 -> Father Process send signal
received signal: 14
signal processing in PID: 4469
PID: 4469 -> Son Process receive signal
Son process finished: PID = 4469

核心優勢總結

  1. 信號屏蔽機制:sa_mask 確保處理函數執行期間不被同類或指定信號中斷,避免競態條件。
  2. 語義統一:POSIX 標準保證跨平台行為一致,不像 signal() 在 BSD/System V 中語義不同。
  3. 擴展性:支持 SA_SIGINFO 獲取詳細信號上下文(siginfo_t、ucontext_t)。
  4. 可恢復系統調用:配合 SA_RESTART 自動重啟被信號中斷的慢系統調用(如 read、wait)。

最佳實踐建議

  • 始終使用 sigaction() 替代 signal()。
  • 信號處理函數中只調用異步信號安全的函數(如 write、_exit、sigaction 本身等),避免調用 printf、malloc 等非安全函數(示例中為演示方便使用了 printf)。
  • 合理設置 sa_mask 防止信號嵌套。
  • 使用 sigemptyset()/sigaddset()/sigdelset() 操作信號集。

掌握 sigaction 是編寫健壯 Linux 系統程序的關鍵一步。下一篇我們將進入管道通信的詳細實戰,敬請期待!

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