MST

星途 面试题库

面试题:C语言在Linux信号处理中如何避免竞态条件

在Linux系统中,使用C语言编写信号处理程序时,常常会遇到竞态条件问题。请阐述可能产生竞态条件的场景,并给出至少两种有效的避免竞态条件的方法,同时结合代码示例说明。
41.6万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

可能产生竞态条件的场景

  1. 信号处理函数与主程序共享全局变量:当主程序和信号处理函数都访问和修改同一个全局变量时,由于信号可能在主程序执行的任何时刻到达,就可能导致数据不一致。例如,主程序正在对一个计数器变量进行递增操作,在递增操作执行到一半时信号到达,信号处理函数也对该计数器进行操作,就会出现竞态。
  2. 异步信号打断系统调用:如果主程序正在执行一个慢速系统调用(如readwriteaccept等),此时信号到达,系统调用可能被中断,信号处理函数执行完毕后,系统调用可能需要重新执行。如果在信号处理函数中修改了与系统调用相关的状态,就可能导致竞态。

避免竞态条件的方法及代码示例

方法一:使用互斥锁(Mutex)

通过互斥锁来保护共享资源,确保同一时间只有一个执行流可以访问共享资源。

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

pthread_mutex_t mutex;
volatile int shared_variable = 0;

void signal_handler(int signum) {
    pthread_mutex_lock(&mutex);
    shared_variable++;
    pthread_mutex_unlock(&mutex);
}

int main() {
    struct sigaction sa;
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, NULL);

    pthread_mutex_init(&mutex, NULL);

    for (int i = 0; i < 5; i++) {
        pthread_mutex_lock(&mutex);
        shared_variable++;
        printf("In main, shared_variable: %d\n", shared_variable);
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }

    pthread_mutex_destroy(&mutex);
    return 0;
}

在上述代码中,pthread_mutex_lockpthread_mutex_unlock函数用于保护shared_variable的访问,确保无论是主程序还是信号处理函数对其操作时都不会出现竞态。

方法二:使用volatile关键字和标志位

使用volatile关键字修饰共享变量,并且通过设置一个标志位来告知信号处理函数和主程序当前的状态,避免同时访问共享资源。

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

volatile int shared_variable = 0;
volatile sig_atomic_t flag = 0;

void signal_handler(int signum) {
    if (!flag) {
        flag = 1;
        shared_variable++;
        flag = 0;
    }
}

int main() {
    struct sigaction sa;
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, NULL);

    for (int i = 0; i < 5; i++) {
        if (!flag) {
            flag = 1;
            shared_variable++;
            printf("In main, shared_variable: %d\n", shared_variable);
            flag = 0;
        }
        sleep(1);
    }

    return 0;
}

这里volatile sig_atomic_t类型的flag作为一个标志位,确保主程序和信号处理函数不会同时访问shared_variablevolatile关键字保证对flagshared_variable的访问不会被编译器优化而导致意外结果。