MST

星途 面试题库

面试题:C语言SIGINT信号处理与系统资源清理的深度优化

在一个使用C语言编写的长时间运行的Linux服务程序中,该程序占用了多种系统资源,如文件描述符、共享内存段、套接字等。要求设计一个完善的SIGINT信号处理机制,不仅要能够在接收到SIGINT信号时安全地清理所有系统资源,还要确保在多进程或多线程环境下的正确性和高效性。请详细说明资源清理的顺序、可能出现的竞态条件及解决方案,并且结合代码示例说明如何通过信号处理函数与其他模块协同工作,以实现系统资源的深度优化和程序的优雅退出。
47.8万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

1. 资源清理顺序

在清理系统资源时,通常遵循以下顺序:

  1. 套接字:关闭套接字以释放网络资源,防止数据泄露或未完成的连接。
  2. 文件描述符:关闭打开的文件描述符,确保文件系统状态正常,避免数据丢失。
  3. 共享内存段:解除映射并释放共享内存,防止内存泄漏。

2. 可能出现的竞态条件及解决方案

  • 竞态条件:在多进程或多线程环境下,多个进程或线程可能同时尝试访问和修改共享资源,导致数据不一致或程序崩溃。例如,一个线程正在清理共享内存,而另一个线程同时尝试访问该共享内存。
  • 解决方案
    • 信号掩码:在进入信号处理函数前,屏蔽SIGINT信号,防止在处理信号过程中再次接收到该信号,导致重入问题。
    • 互斥锁:对于共享资源的访问,使用互斥锁(pthread_mutex_t)来保证同一时间只有一个线程可以访问和修改共享资源。

3. 代码示例

以下是一个简单的C语言示例,展示如何实现上述要求:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define SHM_SIZE 1024

// 共享内存结构体
typedef struct {
    int data;
} SharedData;

// 全局变量
SharedData *shared_memory;
int socket_fd;
int shmid;
pthread_mutex_t mutex;

// 信号处理函数
void sigint_handler(int signum) {
    // 屏蔽SIGINT信号
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    sigprocmask(SIG_BLOCK, &set, NULL);

    // 清理套接字
    close(socket_fd);

    // 清理共享内存
    pthread_mutex_lock(&mutex);
    shmdt(shared_memory);
    shmctl(shmid, IPC_RMID, NULL);
    pthread_mutex_unlock(&mutex);

    // 解除信号屏蔽
    sigprocmask(SIG_UNBLOCK, &set, NULL);

    // 退出程序
    exit(0);
}

// 模拟工作线程
void* worker_thread(void* arg) {
    while (1) {
        // 模拟工作
        pthread_mutex_lock(&mutex);
        shared_memory->data++;
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
    return NULL;
}

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

    // 创建共享内存
    key_t key = ftok(".", 'a');
    shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666);
    shared_memory = (SharedData*)shmat(shmid, NULL, 0);
    shared_memory->data = 0;

    // 创建套接字
    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in servaddr;
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(8080);
    servaddr.sin_addr.s_addr = INADDR_ANY;
    bind(socket_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    listen(socket_fd, 5);

    // 设置信号处理函数
    struct sigaction sa;
    sa.sa_handler = sigint_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, NULL);

    // 创建工作线程
    pthread_t tid;
    pthread_create(&tid, NULL, worker_thread, NULL);

    // 主线程等待
    while (1) {
        sleep(1);
    }

    // 清理资源(理论上不会执行到这里)
    pthread_mutex_destroy(&mutex);
    close(socket_fd);
    shmdt(shared_memory);
    shmctl(shmid, IPC_RMID, NULL);

    return 0;
}

4. 信号处理函数与其他模块协同工作

  • 信号处理函数:负责捕获SIGINT信号,并按照预定顺序清理系统资源。在清理共享资源时,通过互斥锁确保资源的安全访问。
  • 其他模块:如工作线程,在访问共享资源时,先获取互斥锁,完成操作后释放互斥锁,与信号处理函数协同工作,保证系统资源的深度优化和程序的优雅退出。