MST

星途 面试题库

面试题:复杂信号处理场景下C语言函数的综合应用

假设你正在开发一个多线程的Linux应用程序,需要处理SIGTERM、SIGINT等多种信号,同时要保证信号处理的原子性和线程安全性。请详细描述如何选择和使用C语言中的信号处理函数(如sigaction等),以及如何与线程相关机制(如互斥锁、条件变量)配合,以实现一个健壮的信号处理系统,要求给出完整的设计思路和关键代码片段。
19.3万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 信号处理函数选择
    • 使用sigaction函数来设置信号处理函数。sigaction比传统的signal函数更强大,它能提供更细粒度的控制,并且可设置信号处理的一些标志,比如SA_RESTART(使某些被信号中断的系统调用自动重启)。
    • 对于多线程应用,需要注意信号处理函数应该是可重入的。这意味着信号处理函数不能调用不可重入的函数(如mallocprintf等),因为在信号处理期间可能会打断其他线程正在执行的代码,如果调用了不可重入函数可能会导致数据不一致等问题。
  2. 原子性和线程安全性
    • 原子性:通过设置信号掩码来确保信号处理期间不会被其他信号打断,从而保证原子性。在进入信号处理函数前,使用sigprocmask函数阻塞所有可能干扰的信号,处理完后再解除阻塞。
    • 线程安全性:使用互斥锁来保护共享资源。当信号处理函数需要访问共享资源时,先获取互斥锁,处理完后释放互斥锁。对于需要等待某些条件的情况,可以使用条件变量。
  3. 与线程机制配合
    • 主线程负责初始化信号处理,使用pthread_sigmask函数在其他线程中阻塞信号,确保信号由主线程处理。
    • 当主线程接收到信号时,通过条件变量通知其他线程进行相应的处理,其他线程在条件变量上等待,收到通知后获取互斥锁,处理共享资源,然后释放互斥锁。

关键代码片段

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

// 共享资源
int shared_variable = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

// 信号处理函数
void signal_handler(int signum) {
    // 阻塞其他信号
    sigset_t blocked_signals;
    sigfillset(&blocked_signals);
    sigprocmask(SIG_SETMASK, &blocked_signals, NULL);

    // 处理信号相关逻辑,这里以修改共享变量为例
    pthread_mutex_lock(&mutex);
    shared_variable++;
    pthread_mutex_unlock(&mutex);

    // 通知其他线程
    pthread_cond_broadcast(&cond);

    // 解除信号阻塞
    sigemptyset(&blocked_signals);
    sigprocmask(SIG_SETMASK, &blocked_signals, NULL);
}

// 线程函数
void* thread_function(void* arg) {
    // 阻塞信号
    sigset_t blocked_signals;
    sigfillset(&blocked_signals);
    pthread_sigmask(SIG_BLOCK, &blocked_signals, NULL);

    while (1) {
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond, &mutex);
        // 处理共享资源
        printf("Thread received signal, shared variable: %d\n", shared_variable);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    // 设置信号处理函数
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGINT, &sa, NULL);

    // 创建线程
    pthread_t thread;
    pthread_create(&thread, NULL, thread_function, NULL);

    // 主线程逻辑,这里简单地等待信号
    while (1) {
        sleep(1);
    }

    // 清理资源
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    pthread_join(thread, NULL);

    return 0;
}

这段代码实现了一个多线程应用中健壮的信号处理系统。主线程设置信号处理函数,其他线程阻塞信号并在条件变量上等待信号处理函数的通知,通过互斥锁保护共享资源。