MST

星途 面试题库

面试题:C语言Linux复杂信号处理场景下的可重入性

在一个复杂的Linux应用程序中,存在多个信号处理函数,且这些函数可能会被嵌套调用(例如,在处理SIGUSR1信号过程中又收到了SIGALRM信号)。请详细阐述如何确保所有信号处理函数的可重入性,包括对全局变量、标准I/O函数等的处理方式。给出一个包含至少两个不同信号处理函数且存在嵌套调用可能性的代码示例,并说明如何通过设计和代码实现保证其可重入性。
29.5万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

确保信号处理函数可重入性的方法

  1. 全局变量
    • 尽量避免在信号处理函数中使用全局变量。如果必须使用,要考虑加锁机制。例如,使用互斥锁(pthread_mutex_t)来保护对全局变量的访问。在进入信号处理函数时加锁,离开时解锁。
    • 对于可重入的全局变量,确保其在信号处理函数中的操作是原子的,例如简单的整数增减操作(在支持原子操作的系统上)。
  2. 标准I/O函数
    • 标准I/O函数(如printffopen等)通常不是可重入的。在信号处理函数中应避免使用这些函数。
    • 如果需要输出信息,可以考虑使用write函数,它是可重入的。例如,write(STDOUT_FILENO, "message", strlen("message"));

代码示例

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

// 全局变量
int global_var = 0;
pthread_mutex_t mutex;

// SIGUSR1信号处理函数
void sigusr1_handler(int signum) {
    pthread_mutex_lock(&mutex);
    global_var++;
    printf("SIGUSR1 received, global_var: %d\n", global_var);
    pthread_mutex_unlock(&mutex);
    // 模拟嵌套调用,发送SIGALRM信号
    alarm(1);
}

// SIGALRM信号处理函数
void sigalrm_handler(int signum) {
    pthread_mutex_lock(&mutex);
    global_var--;
    printf("SIGALRM received, global_var: %d\n", global_var);
    pthread_mutex_unlock(&mutex);
}

int main() {
    // 初始化互斥锁
    pthread_mutex_init(&mutex, NULL);

    // 注册SIGUSR1信号处理函数
    struct sigaction sa_usr1;
    sa_usr1.sa_handler = sigusr1_handler;
    sigemptyset(&sa_usr1.sa_mask);
    sa_usr1.sa_flags = 0;
    sigaction(SIGUSR1, &sa_usr1, NULL);

    // 注册SIGALRM信号处理函数
    struct sigaction sa_alrm;
    sa_alrm.sa_handler = sigalrm_handler;
    sigemptyset(&sa_alrm.sa_mask);
    sa_alrm.sa_flags = 0;
    sigaction(SIGALRM, &sa_alrm, NULL);

    // 主循环,等待信号
    while (1) {
        printf("Waiting for signals...\n");
        sleep(1);
    }

    // 销毁互斥锁
    pthread_mutex_destroy(&mutex);

    return 0;
}

代码说明

  1. 全局变量处理
    • 声明了全局变量global_var,并使用pthread_mutex_t类型的互斥锁mutex来保护对它的访问。在sigusr1_handlersigalrm_handler信号处理函数中,在对global_var进行操作前加锁,操作完成后解锁。
  2. 标准I/O函数处理
    • 虽然在示例中使用了printf,但实际应用中应避免。这里只是为了简单演示。如果需要输出,可以将printf替换为write函数,如write(STDOUT_FILENO, "SIGUSR1 received, global_var: ", 27);并使用snprintf等函数将global_var的值转换为字符串再输出。
  3. 嵌套调用
    • sigusr1_handler函数中,通过alarm(1)发送了SIGALRM信号,模拟了嵌套调用的情况。由于使用了互斥锁保护全局变量,即使在嵌套调用时,对全局变量的操作也是安全的。