MST

星途 面试题库

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

假设你正在编写一个多线程程序,其中一个线程负责处理SIGTERM信号来执行程序的优雅关闭操作。在处理信号时,可能会与其他线程的操作产生竞争条件,例如共享资源的访问。请描述如何在C语言中使用适当的同步机制(如互斥锁)来避免这些竞争条件,并给出相关代码示例。同时说明信号处理函数中使用同步机制时需要注意的问题。
18.5万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

避免竞争条件的方法

在C语言中,为了避免在处理SIGTERM信号时与其他线程的操作产生竞争条件,可以使用互斥锁(mutex)来保护共享资源。以下是具体步骤:

  1. 初始化互斥锁:在程序开始时,使用pthread_mutex_init函数初始化互斥锁。
  2. 加锁与解锁:在访问共享资源前,使用pthread_mutex_lock函数获取互斥锁,访问完成后,使用pthread_mutex_unlock函数释放互斥锁。
  3. 信号处理函数中使用互斥锁:在处理SIGTERM信号的函数中,同样在访问共享资源前获取互斥锁,完成操作后释放互斥锁。

代码示例

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

// 共享资源
int shared_variable = 0;
// 互斥锁
pthread_mutex_t mutex;

// SIGTERM信号处理函数
void sigterm_handler(int signum) {
    // 获取互斥锁
    pthread_mutex_lock(&mutex);
    printf("Received SIGTERM. Shutting down gracefully...\n");
    // 执行优雅关闭操作,如关闭文件、释放资源等
    // 这里以修改共享变量为例
    shared_variable = -1;
    // 释放互斥锁
    pthread_mutex_unlock(&mutex);
}

// 线程函数
void* thread_function(void* arg) {
    while (1) {
        // 获取互斥锁
        pthread_mutex_lock(&mutex);
        shared_variable++;
        printf("Thread incremented shared_variable: %d\n", shared_variable);
        // 释放互斥锁
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
    return NULL;
}

int main() {
    // 初始化互斥锁
    if (pthread_mutex_init(&mutex, NULL) != 0) {
        printf("\n mutex init has failed\n");
        return 1;
    }

    // 设置SIGTERM信号处理函数
    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;
    }

    pthread_t thread;
    // 创建线程
    if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
        printf("\n ERROR creating thread\n");
        return 1;
    }

    // 等待线程结束
    if (pthread_join(thread, NULL) != 0) {
        printf("\n ERROR joining thread\n");
        return 2;
    }

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

    return 0;
}

信号处理函数中使用同步机制的注意事项

  1. 异步信号安全:信号处理函数应尽量保持简单,避免调用非异步信号安全的函数。在获取和释放互斥锁时,pthread_mutex_lockpthread_mutex_unlock函数通常是异步信号安全的,但要确保使用的函数库支持。
  2. 死锁风险:要注意避免死锁。例如,如果在信号处理函数中获取互斥锁,而主线程或其他线程在持有该互斥锁时被信号中断,就可能导致死锁。应确保信号处理函数中获取互斥锁的逻辑不会与其他线程的锁获取逻辑产生冲突。
  3. 信号掩码:在信号处理函数中,可能需要暂时阻塞其他信号,以避免信号嵌套导致的复杂情况。可以使用sigprocmask函数来设置信号掩码。