MST
星途 面试题库

面试题:进程管理之条件变量在进程同步基础应用

请简述条件变量在进程同步中是如何与互斥锁配合使用来避免竞争条件的,并举例说明一个可能会用到这种配合的场景。
27.9万 热度难度
操作系统进程管理

知识考点

AI 面试

面试题答案

一键面试

条件变量与互斥锁配合避免竞争条件的原理

  1. 互斥锁:互斥锁用于保证在同一时刻只有一个线程或进程能够访问共享资源,防止多个线程或进程同时修改共享数据,从而避免竞争条件。但互斥锁本身只能解决“同时访问”的问题,对于需要根据某些条件来决定是否访问共享资源的情况,单纯的互斥锁无法满足。
  2. 条件变量:条件变量是线程或进程间的一种同步机制,它允许线程或进程在某个条件满足时被唤醒。条件变量通常和互斥锁配合使用,线程在获取互斥锁后,检查共享资源的状态是否满足特定条件。如果不满足,线程会释放互斥锁并在条件变量上等待。当其他线程改变了共享资源的状态使得条件满足时,会通知条件变量,等待在条件变量上的线程会被唤醒,重新获取互斥锁,然后检查条件是否真的满足并继续执行。这样就确保了线程在合适的时机访问共享资源,避免竞争条件。

举例场景

以生产者 - 消费者模型为例:

  1. 场景描述:有一个共享缓冲区,生产者进程向缓冲区中写入数据,消费者进程从缓冲区中读取数据。缓冲区有一定的容量限制,当缓冲区满时,生产者需要等待;当缓冲区空时,消费者需要等待。
  2. 代码示例(以C语言的POSIX线程库为例)
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
int count = 0;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t not_full = PTHREAD_COND_INITIALIZER;
pthread_cond_t not_empty = PTHREAD_COND_INITIALIZER;

void *producer(void *arg) {
    int i;
    for (i = 0; i < 10; i++) {
        pthread_mutex_lock(&mutex);
        while (count == BUFFER_SIZE) {
            pthread_cond_wait(&not_full, &mutex);
        }
        buffer[in] = i;
        printf("Produced: %d\n", buffer[in]);
        in = (in + 1) % BUFFER_SIZE;
        count++;
        pthread_cond_signal(&not_empty);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

void *consumer(void *arg) {
    int i;
    for (i = 0; i < 10; i++) {
        pthread_mutex_lock(&mutex);
        while (count == 0) {
            pthread_cond_wait(&not_empty, &mutex);
        }
        int data = buffer[out];
        printf("Consumed: %d\n", data);
        out = (out + 1) % BUFFER_SIZE;
        count--;
        pthread_cond_signal(&not_full);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_t producer_thread, consumer_thread;
    pthread_create(&producer_thread, NULL, producer, NULL);
    pthread_create(&consumer_thread, NULL, consumer, NULL);
    pthread_join(producer_thread, NULL);
    pthread_join(consumer_thread, NULL);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&not_full);
    pthread_cond_destroy(&not_empty);
    return 0;
}

在这个例子中,互斥锁 mutex 用于保护共享缓冲区 buffer 以及相关的变量 inoutcount。当生产者要向缓冲区写入数据时,先获取互斥锁,然后检查缓冲区是否已满(count == BUFFER_SIZE),如果满了就通过 pthread_cond_wait 释放互斥锁并在 not_full 条件变量上等待。当消费者从缓冲区取出数据后,会通过 pthread_cond_signal 唤醒等待在 not_full 条件变量上的生产者。同理,消费者在读取数据前,先获取互斥锁,检查缓冲区是否为空,为空则在 not_empty 条件变量上等待,生产者写入数据后唤醒消费者。通过这种方式,避免了生产者和消费者对共享缓冲区的竞争条件。