面试题答案
一键面试信号屏蔽和恢复流程
- 定义信号集变量:使用
sigset_t
类型定义一个信号集变量,用于存储要屏蔽的信号。 - 初始化信号集:使用
sigemptyset
函数清空信号集,确保其初始状态不包含任何信号。 - 添加信号到信号集:使用
sigaddset
函数将SIGINT
信号添加到信号集中。 - 屏蔽信号:使用
sigprocmask
函数将信号集应用到进程,从而屏蔽SIGINT
信号。 - 关键代码段执行:在此期间,
SIGINT
信号被屏蔽,程序不会因接收到SIGINT
信号而中断。 - 恢复信号:关键代码段执行完毕后,使用
sigprocmask
函数恢复信号屏蔽前的状态,使进程重新响应SIGINT
信号。
信号集操作函数
sigemptyset(sigset_t *set)
:清空信号集set
,使其不包含任何信号。sigaddset(sigset_t *set, int signum)
:将信号signum
添加到信号集set
中。sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
:how
可以是以下值之一:SIG_BLOCK
:将set
中的信号添加到当前信号屏蔽字。SIG_UNBLOCK
:从当前信号屏蔽字中移除set
中的信号。SIG_SETMASK
:将当前信号屏蔽字设置为set
。
set
是要操作的信号集。oldset
用于保存旧的信号屏蔽字(可选)。
代码示例
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void signal_handler(int signum) {
printf("Caught SIGINT signal\n");
}
int main() {
sigset_t set, oldset;
// 注册信号处理函数
signal(SIGINT, signal_handler);
// 初始化信号集
sigemptyset(&set);
// 添加SIGINT信号到信号集
sigaddset(&set, SIGINT);
// 保存当前信号屏蔽字
sigprocmask(SIG_SETMASK, NULL, &oldset);
// 屏蔽SIGINT信号
sigprocmask(SIG_BLOCK, &set, NULL);
printf("Critical section starts. SIGINT is blocked.\n");
sleep(5); // 模拟关键代码段
printf("Critical section ends. SIGINT will be unblocked.\n");
// 恢复之前的信号屏蔽字
sigprocmask(SIG_SETMASK, &oldset, NULL);
printf("SIGINT is unblocked. Program will exit in 5 seconds.\n");
sleep(5); // 等待信号处理
return 0;
}
屏蔽信号期间SIGINT多次到达的情况分析
当在屏蔽信号期间 SIGINT
信号多次到达时,信号通常不会被排队(POSIX.1 标准允许实现在支持排队的系统上排队信号,但大多数 UNIX 系统默认不排队普通信号)。因此,当解除屏蔽后,进程只会收到一次 SIGINT
信号,并执行相应的信号处理函数。这意味着多次发送的 SIGINT
信号在屏蔽期间被合并为一次。如果需要处理多次信号,可以考虑使用支持信号排队的机制,例如实时信号(SIGRTMIN
到 SIGRTMAX
)。