MST

星途 面试题库

面试题:C语言信号处理函数中的可重入性及安全实现

在Linux C语言编程中,信号处理函数需要考虑可重入性以保证安全。请详细说明可重入函数的特点,并编写一个安全的信号处理函数示例,处理SIGINT信号,在函数中安全地记录信号到来次数到文件,同时解释示例中如何保证可重入性。
31.0万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

可重入函数的特点

  1. 不依赖静态或全局数据:可重入函数在执行过程中不依赖于静态变量或全局变量的状态。如果函数依赖于静态或全局数据,当多个线程或信号处理程序同时调用该函数时,可能会导致数据竞争和未定义行为。
  2. 不调用不可重入函数:可重入函数不能调用不可重入的函数。例如,标准I/O库中的一些函数(如printf)通常不是可重入的,因为它们依赖于内部的静态数据结构。
  3. 具有局部状态:可重入函数应尽量使用局部变量来保存其执行过程中的状态。这些局部变量在函数的每次调用中都是独立的,不会相互干扰。
  4. 可中断执行:可重入函数能够在执行过程中被中断,然后在恢复执行时不会出现问题。这意味着函数的执行不应依赖于特定的执行顺序或不可中断的操作。

安全的信号处理函数示例

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

static volatile sig_atomic_t sigint_count = 0;

void sigint_handler(int signum) {
    // 增加信号计数
    sigint_count++;

    // 打开文件用于追加写入
    int fd = open("sigint_count.txt", O_WRONLY | O_CREAT | O_APPEND, 0644);
    if (fd == -1) {
        // 错误处理
        return;
    }

    char buffer[32];
    // 将计数转换为字符串
    snprintf(buffer, sizeof(buffer), "%d\n", sigint_count);

    // 写入文件
    ssize_t write_result = write(fd, buffer, strlen(buffer));
    if (write_result == -1) {
        // 错误处理
    }

    // 关闭文件
    close(fd);
}

int main() {
    // 注册信号处理函数
    if (signal(SIGINT, sigint_handler) == SIG_ERR) {
        perror("signal");
        return 1;
    }

    while (1) {
        // 主程序执行其他任务
        sleep(1);
    }

    return 0;
}

示例中保证可重入性的方式

  1. 使用sig_atomic_t类型sigint_count变量被声明为volatile sig_atomic_t类型。volatile关键字告诉编译器该变量可能会在程序控制之外被修改(例如在信号处理函数中),sig_atomic_t类型保证了对该变量的访问是原子操作,避免了数据竞争。
  2. 不调用不可重入函数:信号处理函数sigint_handler中没有调用不可重入的函数,如printf。而是使用了可重入的openwriteclose等系统调用函数。
  3. 局部变量使用:函数中使用局部变量buffer来存储格式化后的计数数据,避免了使用静态或全局缓冲区,确保每次调用函数时状态独立。