MST

星途 面试题库

面试题:C语言信号处理函数与竞态条件

在一个多线程的C程序中使用信号处理函数,存在一个共享资源,主线程对其进行读写操作,同时注册了一个信号处理函数来处理SIGUSR1信号,信号处理函数也会访问这个共享资源。请分析可能出现的竞态条件,并说明如何解决。
42.8万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

可能出现的竞态条件

  1. 主线程与信号处理函数之间:主线程在读写共享资源时,可能被信号打断,信号处理函数随即访问共享资源,导致数据不一致。例如,主线程正在进行一个多步骤的写操作(如先修改部分数据,再修改另一部分以完成完整更新),信号处理函数此时介入访问共享资源,可能获取到不完整的数据,或者对不完整的数据状态进行进一步修改,破坏数据的完整性。

解决方法

  1. 使用互斥锁(Mutex)
    • 在主线程读写共享资源前,先获取互斥锁,操作完成后释放互斥锁。
    • 在信号处理函数访问共享资源前,同样获取互斥锁,操作结束后释放。
    • 示例代码(简化示意):
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

pthread_mutex_t mutex;
int shared_resource;

void sig_handler(int signum) {
    pthread_mutex_lock(&mutex);
    // 信号处理函数中对共享资源的操作
    shared_resource++;
    pthread_mutex_unlock(&mutex);
}

void* thread_function(void* arg) {
    pthread_mutex_lock(&mutex);
    // 线程中对共享资源的操作
    shared_resource = 10;
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main() {
    pthread_t thread;
    pthread_mutex_init(&mutex, NULL);

    signal(SIGUSR1, sig_handler);

    pthread_create(&thread, NULL, thread_function, NULL);

    // 主线程其他操作

    pthread_join(thread, NULL);
    pthread_mutex_destroy(&mutex);
    return 0;
}
  1. 使用读写锁(Read - Write Lock):如果主线程读操作较多,写操作较少,可以使用读写锁。主线程读共享资源时获取读锁,写时获取写锁;信号处理函数如果只写,获取写锁。这样可以允许多个读操作同时进行,但写操作时会独占共享资源,避免读写和写写冲突。
  2. 使用原子操作:对于简单的共享资源类型(如整数),可以使用原子操作函数(如__sync_fetch_and_add等,具体取决于编译器和平台)。原子操作保证操作的原子性,即不会被中断,避免竞态条件。例如在信号处理函数和主线程中对shared_resource进行自增操作时可以使用原子操作函数。但原子操作适用场景相对有限,对于复杂数据结构可能无法直接使用。