MST

星途 面试题库

面试题:并发与同步之复杂场景下同步原语的协同

假设有一个生产者 - 消费者模型,其中有多个生产者和多个消费者,并且存在多个共享缓冲区。每个生产者随机选择一个缓冲区写入数据,每个消费者也随机从一个缓冲区读取数据。请使用信号量、互斥锁和条件变量来设计一个高效且正确的同步机制,确保数据的一致性和避免死锁。请详细阐述你的设计方案,并分析可能出现死锁的情况以及如何避免。
39.2万 热度难度
操作系统并发与同步

知识考点

AI 面试

面试题答案

一键面试

设计方案

  1. 数据结构定义

    • 定义共享缓冲区数组 buffer,每个缓冲区可存放一个数据项。
    • 定义一个数组 buffer_status 来记录每个缓冲区的状态(是否为空)。
    • 定义互斥锁 mutex 用于保护共享资源(如 bufferbuffer_status)的访问。
    • 定义条件变量 empty 用于表示缓冲区有空闲位置,full 用于表示缓冲区有数据可读。
    • 定义信号量 semaphore 用于限制同时访问共享缓冲区的线程数量,防止过多线程同时操作导致竞争。
  2. 生产者线程

    void* producer(void* arg) {
        while (true) {
            // 生成数据
            int data = generate_data();
            sem_wait(&semaphore); // 获取信号量,限制并发访问
            pthread_mutex_lock(&mutex);
            while (true) {
                int buffer_index = random_select_buffer();
                if (buffer_status[buffer_index] == EMPTY) {
                    buffer[buffer_index] = data;
                    buffer_status[buffer_index] = FULL;
                    pthread_cond_signal(&full); // 通知缓冲区有数据
                    break;
                }
            }
            pthread_mutex_unlock(&mutex);
            sem_post(&semaphore); // 释放信号量
        }
        return NULL;
    }
    
  3. 消费者线程

    void* consumer(void* arg) {
        while (true) {
            sem_wait(&semaphore); // 获取信号量,限制并发访问
            pthread_mutex_lock(&mutex);
            while (true) {
                int buffer_index = random_select_buffer();
                if (buffer_status[buffer_index] == FULL) {
                    int data = buffer[buffer_index];
                    buffer_status[buffer_index] = EMPTY;
                    pthread_cond_signal(&empty); // 通知缓冲区有空闲位置
                    process_data(data);
                    break;
                } else {
                    pthread_cond_wait(&full, &mutex); // 等待缓冲区有数据
                }
            }
            pthread_mutex_unlock(&mutex);
            sem_post(&semaphore); // 释放信号量
        }
        return NULL;
    }
    

可能出现死锁的情况及避免方法

  1. 死锁情况分析

    • 情况一:资源分配不当:如果没有信号量 semaphore 限制并发访问,可能会出现大量生产者和消费者线程同时竞争共享缓冲区,导致每个线程都占有部分资源(如互斥锁),但又在等待其他线程释放资源,从而形成死锁。
    • 情况二:条件变量等待问题:如果在 pthread_cond_wait 时没有正确处理,比如没有在等待前获取互斥锁,或者在等待返回后没有重新获取互斥锁,可能会导致线程在等待过程中被其他线程修改共享资源状态,从而错过条件变量的信号,造成死锁。
  2. 避免死锁方法

    • 使用信号量限制并发:通过信号量 semaphore 限制同时访问共享缓冲区的线程数量,避免过多线程竞争资源,从而防止因资源分配不当导致的死锁。
    • 正确使用条件变量:在 pthread_cond_wait 前必须获取互斥锁,并且在 pthread_cond_wait 返回后重新获取互斥锁,确保在等待过程中共享资源状态不会被非法修改,避免错过条件变量信号导致的死锁。同时,在条件变量等待的循环中检查条件,防止虚假唤醒。