嵌入式Linux:信号掩码

2026-10-041

在 Linux 系统中,内核为每个进程维护一个信号掩码,也就是一组暂时阻塞的信号。进程收到被屏蔽的信号时,信号不会丢失,而是保持挂起状态,直到它从掩码中移除后再传递给进程处理。

向信号掩码添加信号的方式

通过 signal() 或 sigaction()

为信号设置处理方式时,信号通常会自动加入进程的掩码,避免处理函数重入。对于 sigaction(),如果设置 SA_NODEFER,当前信号不会被自动阻塞;处理函数返回后,该信号会从掩码中移除。

通过 sa_mask 参数

sigaction() 的 sa_mask 可以指定一组额外信号。它们会在处理函数执行期间被临时阻塞,处理函数结束后恢复。

通过 sigprocmask()

sigprocmask() 允许程序显式添加、移除或替换信号掩码,适合需要精细控制信号屏蔽范围的场景。本文重点介绍它的用法。

函数原型

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

参数说明

  • how 决定操作方式:
    • SIG_BLOCK:把 set 中的信号加入当前掩码。
    • SIG_UNBLOCK:从当前掩码中移除 set 中的信号。
    • SIG_SETMASK:直接用 set 替换当前掩码。
  • set 指向要添加或移除的信号集;传入 NULL 时不改变当前掩码。
  • oldset 不为 NULL 时,内核会在修改前把旧掩码保存到它指向的信号集中,便于之后恢复。
  • 成功返回 0;失败返回 -1,并设置 errno。

阻塞并解除阻塞 SIGINT

下面的程序先阻塞 SIGINT,随后解除阻塞,并检查每次系统调用的返回值:

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

int main(void) {
    int ret;
    sigset_t sig_set;

    // 初始化信号集为空
    sigemptyset(&sig_set);

    // 向信号集中添加 SIGINT
    sigaddset(&sig_set, SIGINT);

    // 阻塞 SIGINT
    ret = sigprocmask(SIG_BLOCK, &sig_set, NULL);
    if (ret == -1) {
        perror("sigprocmask error");
        exit(EXIT_FAILURE);
    }

    printf("SIGINT blocked\n");

    // 解除 SIGINT 阻塞
    ret = sigprocmask(SIG_UNBLOCK, &sig_set, NULL);
    if (ret == -1) {
        perror("sigprocmask error");
        exit(EXIT_FAILURE);
    }

    printf("SIGINT unblocked\n");
    return 0;
}

信号掩码是 Linux 进程信号处理中的关键机制。结合 signal()、sigaction() 和 sigprocmask(),程序可以明确哪些信号暂时阻塞、哪些信号立即传递,从而减少信号干扰造成的竞态问题。

来源:嵌入式Linux:信号掩码(CSDN,原作者“不脱发的程序猿”,CC BY-SA 4.0)

创作许可协议

本项目采用 CC BY(署名) 进行许可。

评论(0)
- 没有更多了 -