MST

星途 面试题库

面试题:并发与同步下复杂场景的条件变量应用

假设有一个多线程程序,其中生产者线程不断生成数据并放入缓冲区,消费者线程从缓冲区取出数据进行处理。当缓冲区满时生产者线程需要等待,当缓冲区空时消费者线程需要等待。请使用条件变量和互斥锁设计一个实现该场景的伪代码,并分析可能出现的竞态条件及如何避免。
45.6万 热度难度
操作系统并发与同步

知识考点

AI 面试

面试题答案

一键面试

伪代码实现

// 定义缓冲区大小
const int bufferSize = 10; 
// 缓冲区
int buffer[bufferSize]; 
// 缓冲区索引
int in = 0; 
int out = 0; 

// 互斥锁
Mutex mutex; 
// 条件变量
ConditionVariable notFull; 
ConditionVariable notEmpty; 

// 生产者线程函数
void Producer() {
    while (true) {
        int data = generateData(); 
        mutex.lock(); 
        while ((in + 1) % bufferSize == out) { 
            notFull.wait(mutex); 
        }
        buffer[in] = data; 
        in = (in + 1) % bufferSize; 
        notEmpty.signal(); 
        mutex.unlock(); 
    }
}

// 消费者线程函数
void Consumer() {
    while (true) {
        mutex.lock(); 
        while (in == out) { 
            notEmpty.wait(mutex); 
        }
        int data = buffer[out]; 
        out = (out + 1) % bufferSize; 
        notFull.signal(); 
        mutex.unlock(); 
        processData(data); 
    }
}

可能出现的竞态条件及避免方法

  1. 竞态条件
    • 多个线程同时访问和修改缓冲区的索引 inout 可能导致数据不一致。例如,当生产者线程和消费者线程同时尝试更新 inout 时,可能会丢失更新。
    • 缓冲区状态判断与实际操作之间可能存在时间差。比如,在判断缓冲区不满后,还没来得及放入数据,其他线程可能已经改变了缓冲区状态。
  2. 避免方法
    • 使用互斥锁 mutex 来保护对缓冲区以及相关索引 inout 的访问。在访问这些共享资源前加锁,访问结束后解锁,确保同一时间只有一个线程能操作共享资源。
    • 使用条件变量 notFullnotEmpty 来处理线程的等待和唤醒。在判断缓冲区状态(满或空)后,如果不满足条件,线程通过条件变量等待,避免无效的循环检查,同时防止在等待期间其他线程改变缓冲区状态而错过机会。当状态改变满足条件时,通过条件变量唤醒等待的线程。