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

APUE 信號處理實戰:sigprocmask 與 sigpending 範例詳解

編輯:Linux 教學

程式目的

演示如何使用 sigprocmask 暫時阻塞特定信號(SIGQUIT),並透過 sigpending 檢查未決信號,驗證信號阻塞期間產生的信號不會丟失,解除阻塞後立即被處理。

完整程式碼

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void error_quit(const char *str) {
    fprintf(stderr, "%s\n", str);
    exit(1);
}

void sig_quit(int signo) {
    printf("caught SIGQUIT\n");
    if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
        error_quit("can't reset SIGQUIT");
}

int main(void) {
    sigset_t newmask, oldmask, pendmask;

    // 設置 SIGQUIT 處理函數
    if (signal(SIGQUIT, sig_quit) == SIG_ERR)
        error_quit("can't catch SIGQUIT");

    // 初始化並添加 SIGQUIT 到新屏蔽集
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGQUIT);

    // 阻塞 SIGQUIT,保存舊屏蔽集
    if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
        error_quit("SIG_BLOCK error");

    sleep(5);  // 此期間按 Ctrl+\ 產生 SIGQUIT,將變為未決

    // 檢查未決信號
    if (sigpending(&pendmask) < 0)
        error_quit("sigpending error");
    if (sigismember(&pendmask, SIGQUIT))
        printf("\nSIGQUIT pending\n");

    // 解除阻塞,恢復原屏蔽集
    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
        error_quit("SIG_SETMASK error");
    printf("SIGQUIT unblocked\n");

    sleep(5);  // 此期間再次按 Ctrl+\ 將觸發預設動作(退出)
    return 0;
}

執行結果分析

$ ./temp
^\                # 第 5 秒內按下 Ctrl+\
SIGQUIT pending   # sleep 返回,檢測到未決
caught SIGQUIT    # sigprocmask 解除阻塞前,處理函數已執行
SIGQUIT unblocked
^\                # 再次按下,觸發預設動作退出

若在阻塞期間連按多次 Ctrl+\,解除阻塞後僅執行一次處理函數,驗證標準信號不排隊特性。

核心結論

  1. 進程阻塞信號期間產生的同類信號,全部轉為「未決」狀態保留。
  2. sigprocmask 解除阻塞的動作在函數返回之前已完成,未決信號隨即被處理。
  3. 標準信號不排隊:阻塞期間多次產生,解除阻塞後僅處理一次。

註解補充

「未決」是狀態,「阻塞」是開關動作。APUE 例題中,sleep 期間信號被阻塞,故處於未決狀態;sigprocmask 關閉阻塞開關瞬間,未決信號立即得到處理,且發生在 sigprocmask 返回之前。

Copyright © Windows教程網 All Rights Reserved