MST
星途 面试题库

面试题:C语言复杂Linux信号处理场景下的并发优化

在一个高并发的Linux应用程序中,用C语言编写。该程序需要处理多种信号,如`SIGUSR1`、`SIGUSR2`等,同时涉及大量的文件I/O操作和多线程并发任务。信号处理函数可能会打断正在进行的文件I/O操作或线程任务。请设计一个全面的解决方案,确保信号处理与并发任务之间的高效协同,避免数据损坏和死锁等问题,详细阐述设计思路并给出核心代码框架。
38.2万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 信号处理函数设计:信号处理函数应尽量简单,避免复杂操作,防止阻塞其他信号处理或干扰主线程及其他线程。通常信号处理函数只是设置一个标志位,告知主线程或相关线程信号已到达。
  2. 线程安全考虑:对于共享资源(如文件描述符、全局变量等),在多线程环境下访问时,需要使用互斥锁(pthread_mutex_t)或读写锁(pthread_rwlock_t)来保证线程安全。
  3. 文件I/O操作:在信号处理函数可能打断文件I/O操作的情况下,可以使用fcntl设置文件描述符为非阻塞模式,或者使用aio系列异步I/O函数,以避免信号处理函数打断阻塞的I/O操作导致的数据一致性问题。
  4. 同步机制:使用条件变量(pthread_cond_t)来实现线程间的同步,确保在合适的时机处理信号相关的任务。

核心代码框架

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

// 定义标志位
volatile sig_atomic_t sigusr1_received = 0;
volatile sig_atomic_t sigusr2_received = 0;

// 定义互斥锁和条件变量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

// 信号处理函数
void sigusr1_handler(int signum) {
    pthread_mutex_lock(&mutex);
    sigusr1_received = 1;
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
}

void sigusr2_handler(int signum) {
    pthread_mutex_lock(&mutex);
    sigusr2_received = 1;
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
}

// 线程函数示例
void* thread_function(void* arg) {
    while (1) {
        pthread_mutex_lock(&mutex);
        while (!sigusr1_received &&!sigusr2_received) {
            pthread_cond_wait(&cond, &mutex);
        }
        if (sigusr1_received) {
            // 处理SIGUSR1相关任务
            printf("Handling SIGUSR1\n");
            sigusr1_received = 0;
        }
        if (sigusr2_received) {
            // 处理SIGUSR2相关任务
            printf("Handling SIGUSR2\n");
            sigusr2_received = 0;
        }
        pthread_mutex_unlock(&mutex);
        // 执行其他任务
    }
    return NULL;
}

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

    sa.sa_handler = sigusr2_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGUSR2, &sa, NULL);

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

    // 主线程执行文件I/O等其他任务
    int fd = open("test.txt", O_WRONLY | O_CREAT, 0644);
    if (fd == -1) {
        perror("open");
        return 1;
    }
    // 设置文件描述符为非阻塞模式
    int flags = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);

    // 主线程继续执行其他任务
    while (1) {
        // 执行文件I/O操作
        write(fd, "data", 4);
        // 其他任务
        sleep(1);
    }

    // 清理资源
    pthread_cancel(tid);
    pthread_join(tid, NULL);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    close(fd);
    return 0;
}

在上述代码中:

  1. 定义了两个标志位sigusr1_receivedsigusr2_received,用于标记信号是否到达。
  2. 使用互斥锁mutex和条件变量cond来实现线程间的同步。
  3. 信号处理函数sigusr1_handlersigusr2_handler在接收到信号时设置标志位并通过条件变量通知相关线程。
  4. 线程函数thread_function等待信号相关标志位被设置,并处理相应任务。
  5. 主线程执行文件I/O操作,并将文件描述符设置为非阻塞模式,以避免信号打断阻塞的I/O操作。最后清理相关资源。