MST

星途 面试题库

面试题:C语言信号捕获与多线程编程的结合及问题解决

在一个多线程的C语言程序中,主线程创建了若干子线程进行不同任务,同时需要捕获SIGUSR1信号来执行特定的全局清理操作。然而,在实际运行中发现,信号处理函数有时无法正确执行清理操作。请分析可能的原因,从信号处理机制和多线程编程原理的角度阐述,并给出完整的代码解决方案,包括如何正确地设置信号掩码、线程同步等操作。
49.0万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

可能原因分析

  1. 信号竞争问题:在多线程环境下,信号可能会在任意时刻到达,而不同线程可能同时访问共享资源。如果信号处理函数和其他线程同时操作共享资源,可能会导致数据竞争,使得清理操作执行不正确。
  2. 信号掩码设置不当:每个线程都有自己的信号掩码。如果主线程在创建子线程后没有正确设置信号掩码,子线程可能会意外地捕获信号,干扰主线程的信号处理逻辑。
  3. 线程同步问题:清理操作可能依赖于某些子线程的完成状态。如果在清理操作执行时,相关子线程还未完成任务,可能导致清理不完整或错误。

代码解决方案

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

// 全局变量,用于标记是否需要清理
volatile sig_atomic_t need_cleanup = 0;

// 共享资源
int shared_resource = 0;

// 线程同步互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// 线程同步条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

// 子线程任务函数
void* thread_task(void* arg) {
    // 子线程屏蔽SIGUSR1信号
    sigset_t sigset;
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGUSR1);
    pthread_sigmask(SIG_BLOCK, &sigset, NULL);

    // 模拟子线程任务
    for (int i = 0; i < 1000000; i++) {
        pthread_mutex_lock(&mutex);
        shared_resource++;
        pthread_mutex_unlock(&mutex);
    }

    // 任务完成,通知主线程
    pthread_mutex_lock(&mutex);
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);

    return NULL;
}

// 信号处理函数
void signal_handler(int signum) {
    // 设置清理标记
    need_cleanup = 1;
}

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

    // 创建子线程
    pthread_t threads[5];
    for (int i = 0; i < 5; i++) {
        pthread_create(&threads[i], NULL, thread_task, NULL);
    }

    // 主线程等待子线程完成
    for (int i = 0; i < 5; i++) {
        pthread_join(threads[i], NULL);
    }

    // 等待信号触发清理操作
    while (!need_cleanup) {
        sleep(1);
    }

    // 执行清理操作
    pthread_mutex_lock(&mutex);
    printf("Cleaning up shared_resource: %d\n", shared_resource);
    shared_resource = 0;
    pthread_mutex_unlock(&mutex);

    // 销毁互斥锁和条件变量
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);

    return 0;
}

代码说明

  1. 信号处理函数signal_handler函数设置了need_cleanup标记,表明需要执行清理操作。
  2. 子线程任务:每个子线程屏蔽SIGUSR1信号,避免干扰主线程的信号处理。子线程完成任务后,通过条件变量通知主线程。
  3. 主线程:主线程等待所有子线程完成任务,然后等待SIGUSR1信号。信号触发后,主线程执行清理操作,确保共享资源得到正确清理。同时,使用互斥锁保护共享资源的访问,防止数据竞争。最后销毁互斥锁和条件变量。