MST
星途 面试题库

面试题:C语言信号处理中的竞态条件问题

假设你正在编写一个多线程的C程序,并且其中一个线程需要捕获SIGTERM信号来进行优雅关闭。在处理信号时,可能会出现竞态条件(race condition),请描述可能出现竞态条件的场景是什么,并提出至少一种解决方案来避免这种竞态条件,用C语言代码示例说明解决方案。
38.5万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

可能出现竞态条件的场景

  1. 信号处理函数与主线程共享资源:例如,主线程和信号处理函数都访问并修改同一个全局变量is_shutdown,用于标识程序是否要关闭。主线程可能在检查is_shutdown后,还未来得及进行关闭操作时,信号处理函数修改了is_shutdown,导致主线程的逻辑被打乱。
  2. 信号处理函数中断临界区:如果主线程正在执行一段不能被中断的代码(临界区),例如正在进行文件操作的中间阶段,此时信号处理函数被触发,可能导致文件操作不完整,数据损坏。

解决方案

  1. 使用互斥锁(Mutex):通过互斥锁来保护共享资源,确保同一时间只有一个线程可以访问和修改共享资源。

以下是C语言代码示例:

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

pthread_mutex_t mutex;
int is_shutdown = 0;

// 信号处理函数
void sigterm_handler(int signum) {
    pthread_mutex_lock(&mutex);
    is_shutdown = 1;
    pthread_mutex_unlock(&mutex);
}

// 线程函数
void* thread_function(void* arg) {
    while (1) {
        pthread_mutex_lock(&mutex);
        if (is_shutdown) {
            pthread_mutex_unlock(&mutex);
            break;
        }
        pthread_mutex_unlock(&mutex);
        // 线程执行的其他任务
        printf("Thread is running...\n");
        sleep(1);
    }
    printf("Thread is shutting down...\n");
    return NULL;
}

int main() {
    pthread_t thread;
    struct sigaction sa;

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

    // 设置信号处理
    sa.sa_handler = sigterm_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGTERM, &sa, NULL) == -1) {
        perror("sigaction");
        return 1;
    }

    // 创建线程
    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;
}
  1. 使用原子操作:对于简单的共享变量(如int类型),可以使用原子操作来避免竞态条件。在C11标准中引入了<stdatomic.h>头文件提供原子类型和操作。

以下是代码示例:

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

atomic_int is_shutdown = ATOMIC_VAR_INIT(0);

// 信号处理函数
void sigterm_handler(int signum) {
    atomic_store(&is_shutdown, 1);
}

// 线程函数
void* thread_function(void* arg) {
    while (1) {
        if (atomic_load(&is_shutdown)) {
            break;
        }
        // 线程执行的其他任务
        printf("Thread is running...\n");
        sleep(1);
    }
    printf("Thread is shutting down...\n");
    return NULL;
}

int main() {
    pthread_t thread;
    struct sigaction sa;

    // 设置信号处理
    sa.sa_handler = sigterm_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGTERM, &sa, NULL) == -1) {
        perror("sigaction");
        return 1;
    }

    // 创建线程
    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;
    }

    return 0;
}