MST

星途 面试题库

面试题:C语言多线程信号处理中的竞争条件及解决方案

在Linux C语言多线程编程涉及信号处理时,经常会出现竞争条件。请举例说明一种可能出现的竞争条件场景,并阐述至少两种有效的解决方案,同时用代码简单示意如何实现其中一种方案。
36.8万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

竞争条件场景举例

假设主线程正在处理一个信号,该信号用于通知程序进行某些资源的清理工作。同时,一个子线程正在尝试访问并修改与该清理操作相关的资源。例如,主线程接收到SIGTERM信号,准备清理一个共享的文件描述符列表,而此时子线程正准备向该列表中添加新的文件描述符。这就可能导致数据不一致,因为主线程可能在子线程添加操作完成之前就开始清理,从而造成数据丢失或错误的清理操作。

解决方案

  1. 使用互斥锁(Mutex):通过互斥锁来保护共享资源,确保同一时间只有一个线程能够访问和修改这些资源。当一个线程获取到互斥锁后,其他线程必须等待该锁被释放才能访问共享资源。
  2. 信号掩码(Signal Masking):在子线程中屏蔽掉可能引发竞争条件的信号,只在主线程中处理这些信号。这样可以避免子线程在处理共享资源时被信号打断。

代码示例(使用互斥锁方案)

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

pthread_mutex_t mutex;
int shared_resource = 0;

void* thread_function(void* arg) {
    // 尝试获取互斥锁
    pthread_mutex_lock(&mutex);
    shared_resource++;
    printf("子线程修改共享资源: %d\n", shared_resource);
    // 释放互斥锁
    pthread_mutex_unlock(&mutex);
    return NULL;
}

void signal_handler(int signum) {
    // 尝试获取互斥锁
    pthread_mutex_lock(&mutex);
    printf("接收到信号,正在清理共享资源: %d\n", shared_resource);
    // 这里进行清理操作
    // 释放互斥锁
    pthread_mutex_unlock(&mutex);
}

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

    // 设置信号处理函数
    signal(SIGTERM, signal_handler);

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

    // 等待子线程结束
    if (pthread_join(thread, NULL) != 0) {
        perror("pthread_join");
        return 1;
    }

    // 销毁互斥锁
    pthread_mutex_destroy(&mutex);
    return 0;
}

在上述代码中,使用互斥锁 mutex 来保护共享资源 shared_resource。子线程在修改 shared_resource 前获取互斥锁,信号处理函数在清理资源前也获取互斥锁,这样就能避免竞争条件。