MST

星途 面试题库

面试题:C语言下Linux信号集操作中的信号屏蔽与恢复处理

在Linux C语言编程中,假设你有一个关键代码段,需要暂时屏蔽SIGINT信号以避免程序在执行此代码段时被中断。请详细说明信号屏蔽和恢复的完整流程,包括使用哪些信号集操作函数,并给出相应的代码示例。同时,分析如果在屏蔽信号期间,SIGINT信号多次到达,解除屏蔽后会发生什么情况。
44.2万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

信号屏蔽和恢复流程

  1. 定义信号集变量:使用 sigset_t 类型定义一个信号集变量,用于存储要屏蔽的信号。
  2. 初始化信号集:使用 sigemptyset 函数清空信号集,确保其初始状态不包含任何信号。
  3. 添加信号到信号集:使用 sigaddset 函数将 SIGINT 信号添加到信号集中。
  4. 屏蔽信号:使用 sigprocmask 函数将信号集应用到进程,从而屏蔽 SIGINT 信号。
  5. 关键代码段执行:在此期间,SIGINT 信号被屏蔽,程序不会因接收到 SIGINT 信号而中断。
  6. 恢复信号:关键代码段执行完毕后,使用 sigprocmask 函数恢复信号屏蔽前的状态,使进程重新响应 SIGINT 信号。

信号集操作函数

  1. sigemptyset(sigset_t *set):清空信号集 set,使其不包含任何信号。
  2. sigaddset(sigset_t *set, int signum):将信号 signum 添加到信号集 set 中。
  3. 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 信号在屏蔽期间被合并为一次。如果需要处理多次信号,可以考虑使用支持信号排队的机制,例如实时信号(SIGRTMINSIGRTMAX)。