嵌入式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)



