MST

星途 面试题库

面试题:C语言Linux异步I/O异步通知机制中的竞争条件处理

在使用C语言实现Linux异步I/O的异步通知机制时,可能会遇到竞争条件。请举例说明可能出现竞争条件的场景,并阐述如何使用互斥锁、信号量等机制来避免这些竞争条件,以保证程序的正确性和稳定性。
22.7万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

可能出现竞争条件的场景举例

假设在一个基于C语言实现Linux异步I/O异步通知机制的程序中,有多个线程会同时处理异步I/O完成后的通知。当I/O操作完成,内核会发送通知信号,多个线程可能同时接收到这个信号并尝试处理。例如,在处理函数中可能有对共享资源(如全局计数器)的操作:

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

// 全局计数器
int counter = 0;

// 模拟I/O完成处理函数
void io_completion_handler() {
    counter++;
    printf("Counter incremented to %d\n", counter);
}

// 线程函数
void* thread_function(void* arg) {
    // 模拟接收到I/O完成通知
    io_completion_handler();
    return NULL;
}

在这个例子中,如果多个线程同时调用io_completion_handler,由于对counter的操作不是原子的,就会出现竞争条件,导致counter的值可能并不是预期的正确累加结果。

使用互斥锁避免竞争条件

互斥锁(pthread_mutex_t)可以用来保证同一时间只有一个线程能够访问共享资源。修改上述代码如下:

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

// 全局计数器
int counter = 0;
// 互斥锁
pthread_mutex_t mutex;

// 模拟I/O完成处理函数
void io_completion_handler() {
    // 加锁
    pthread_mutex_lock(&mutex);
    counter++;
    printf("Counter incremented to %d\n", counter);
    // 解锁
    pthread_mutex_unlock(&mutex);
}

// 线程函数
void* thread_function(void* arg) {
    // 模拟接收到I/O完成通知
    io_completion_handler();
    return NULL;
}

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

    pthread_t threads[10];
    for (int i = 0; i < 10; i++) {
        pthread_create(&threads[i], NULL, thread_function, NULL);
    }

    for (int i = 0; i < 10; i++) {
        pthread_join(threads[i], NULL);
    }

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

io_completion_handler函数中,通过pthread_mutex_lockpthread_mutex_unlock来保护对counter的操作,这样就避免了竞争条件。

使用信号量避免竞争条件

信号量(sem_t)可以控制同时访问共享资源的线程数量,也能用来避免竞争条件。以下是使用信号量修改后的代码:

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>

// 全局计数器
int counter = 0;
// 信号量
sem_t sem;

// 模拟I/O完成处理函数
void io_completion_handler() {
    // 等待信号量
    sem_wait(&sem);
    counter++;
    printf("Counter incremented to %d\n", counter);
    // 释放信号量
    sem_post(&sem);
}

// 线程函数
void* thread_function(void* arg) {
    // 模拟接收到I/O完成通知
    io_completion_handler();
    return NULL;
}

int main() {
    // 初始化信号量,初始值设为1
    sem_init(&sem, 0, 1);

    pthread_t threads[10];
    for (int i = 0; i < 10; i++) {
        pthread_create(&threads[i], NULL, thread_function, NULL);
    }

    for (int i = 0; i < 10; i++) {
        pthread_join(threads[i], NULL);
    }

    // 销毁信号量
    sem_destroy(&sem);
    return 0;
}

在这个例子中,通过sem_waitsem_post函数配合,保证同一时间只有一个线程能进入对共享资源counter的操作区域,从而避免竞争条件。