MST
星途 面试题库

面试题:C语言Linux信号处理与多线程并发协同

在Linux系统下,使用C语言编写一个程序,其中包含多线程,并且有一个信号处理函数用于处理`SIGTERM`信号。当`SIGTERM`信号到达时,信号处理函数需要通知所有线程进行安全的退出操作。请说明如何通过信号处理函数与多线程之间的通信机制来实现这一功能,同时要考虑线程同步和竞态条件问题,写出关键代码片段并解释。
23.8万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

1. 信号处理函数与多线程通信机制

  • 共享变量:通过定义一个共享的全局变量,例如volatile sig_atomic_t stop_flag,信号处理函数在接收到SIGTERM信号时设置这个标志,线程通过检查这个标志来决定是否退出。
  • 条件变量:结合互斥锁和条件变量来实现线程间的同步。当stop_flag被设置时,主线程可以通过条件变量通知其他线程。

2. 关键代码片段及解释

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

// 定义共享变量
volatile sig_atomic_t stop_flag = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

// 信号处理函数
void sig_handler(int signum) {
    pthread_mutex_lock(&mutex);
    stop_flag = 1;
    pthread_cond_broadcast(&cond); // 通知所有等待在条件变量上的线程
    pthread_mutex_unlock(&mutex);
}

// 线程函数
void* thread_function(void* arg) {
    pthread_mutex_lock(&mutex);
    while (!stop_flag) {
        // 等待条件变量,同时释放互斥锁
        pthread_cond_wait(&cond, &mutex); 
    }
    pthread_mutex_unlock(&mutex);
    printf("Thread is exiting...\n");
    return NULL;
}

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

    // 创建线程
    if (pthread_create(&tid, NULL, thread_function, NULL) != 0) {
        perror("pthread_create");
        return 1;
    }

    // 主线程继续执行其他任务
    while (!stop_flag) {
        sleep(1);
    }

    // 等待线程退出
    pthread_join(tid, NULL);

    // 清理资源
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);

    return 0;
}
  • 共享变量stop_flagvolatile sig_atomic_t类型保证了对该变量的访问是原子操作,并且防止编译器优化对其访问的顺序。信号处理函数可以安全地修改这个变量,线程也能安全地读取这个变量。
  • 信号处理函数sig_handler:在接收到SIGTERM信号时,首先获取互斥锁,设置stop_flag,然后通过pthread_cond_broadcast通知所有等待在条件变量cond上的线程,最后释放互斥锁。
  • 线程函数thread_function:线程在开始时获取互斥锁,然后通过pthread_cond_wait等待条件变量。这个函数会自动释放互斥锁并阻塞线程,当条件变量被通知时,它会重新获取互斥锁并检查stop_flag。如果stop_flag为真,则退出线程。
  • 主线程:在主线程中,注册信号处理函数,创建线程并等待stop_flag被设置。当stop_flag被设置后,主线程调用pthread_join等待线程退出,最后清理互斥锁和条件变量。通过这种方式,有效地避免了竞态条件,实现了信号处理函数与多线程之间的安全通信和线程同步。