MST

星途 面试题库

面试题:C语言Linux定时器信号处理中的竞态条件处理

在Linux C语言开发中,当定时器信号处理函数与主程序共享某些资源时,可能会出现竞态条件。请阐述如何识别和处理这种竞态条件,结合定时器信号处理场景,给出具体的解决思路和代码示例(如使用互斥锁等机制)。
48.8万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

识别竞态条件

  1. 分析共享资源:明确定时器信号处理函数与主程序共同访问和修改的变量、数据结构等资源。例如,全局变量的读写操作,特别是在信号处理函数可能异步修改,而主程序也在正常流程中访问和修改的情况下。
  2. 检查访问时机:考虑信号可能在主程序执行对共享资源操作的任何时刻到达,比如在主程序读取一个变量后,还未完成对其修改时,信号处理函数修改了该变量,就会导致数据不一致。

处理竞态条件

  1. 使用互斥锁(Mutex)
    • 思路:在访问共享资源前,主程序和信号处理函数都获取互斥锁,访问结束后释放互斥锁。这样同一时间只有一个执行流(主程序或信号处理函数)能访问共享资源,避免竞态条件。
    • 代码示例
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>

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

// 定时器信号处理函数
void timer_handler(int signum) {
    // 加锁
    pthread_mutex_lock(&mutex);
    shared_variable++;
    printf("Signal handler: shared_variable = %d\n", shared_variable);
    // 解锁
    pthread_mutex_unlock(&mutex);
}

int main() {
    struct sigaction sa;
    struct itimerval timer;

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

    // 配置信号处理函数
    sa.sa_handler = timer_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGVTALRM, &sa, NULL);

    // 设置定时器
    timer.it_value.tv_sec = 1;
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 1;
    timer.it_interval.tv_usec = 0;
    setitimer(ITIMER_VIRTUAL, &timer, NULL);

    while (1) {
        // 加锁
        pthread_mutex_lock(&mutex);
        printf("Main program: shared_variable = %d\n", shared_variable);
        // 解锁
        pthread_mutex_unlock(&mutex);
        sleep(2);
    }

    // 清理互斥锁
    pthread_mutex_destroy(&mutex);
    return 0;
}
  1. 使用信号掩码(Signal Masking)
    • 思路:在主程序对共享资源进行关键操作时,阻塞定时器信号,操作完成后再解除阻塞。这样可以防止信号处理函数在关键操作期间打断主程序。
    • 代码示例
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

// 共享资源
int shared_variable = 0;

// 定时器信号处理函数
void timer_handler(int signum) {
    shared_variable++;
    printf("Signal handler: shared_variable = %d\n", shared_variable);
}

int main() {
    struct sigaction sa;
    struct itimerval timer;
    sigset_t set;

    // 配置信号处理函数
    sa.sa_handler = timer_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGVTALRM, &sa, NULL);

    // 设置定时器
    timer.it_value.tv_sec = 1;
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 1;
    timer.it_interval.tv_usec = 0;
    setitimer(ITIMER_VIRTUAL, &timer, NULL);

    // 初始化信号集
    sigemptyset(&set);
    sigaddset(&set, SIGVTALRM);

    while (1) {
        // 阻塞信号
        sigprocmask(SIG_BLOCK, &set, NULL);
        printf("Main program: shared_variable = %d\n", shared_variable);
        // 解除阻塞信号
        sigprocmask(SIG_UNBLOCK, &set, NULL);
        sleep(2);
    }
    return 0;
}

以上两种方法分别通过互斥锁和信号掩码来处理定时器信号处理函数与主程序之间共享资源的竞态条件,在实际应用中可根据具体场景选择合适的方法。