面试题答案
一键面试以下是使用C语言在Linux下通过条件变量实现生产者 - 消费者模型的代码示例,同时考虑了避免虚假唤醒问题,并对同步机制进行了优化:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.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 item = 1;
while (1) {
// 加锁
pthread_mutex_lock(&mutex);
// 避免虚假唤醒,只有缓冲区不满时才生产
while (count == BUFFER_SIZE) {
pthread_cond_wait(¬_full, &mutex);
}
buffer[in] = item;
printf("Produced: %d\n", item);
in = (in + 1) % BUFFER_SIZE;
count++;
// 通知消费者缓冲区有数据
pthread_cond_signal(¬_empty);
// 解锁
pthread_mutex_unlock(&mutex);
item++;
sleep(1);
}
return NULL;
}
// 消费者函数
void* consumer(void* arg) {
while (1) {
// 加锁
pthread_mutex_lock(&mutex);
// 避免虚假唤醒,只有缓冲区不为空时才消费
while (count == 0) {
pthread_cond_wait(¬_empty, &mutex);
}
int item = buffer[out];
printf("Consumed: %d\n", item);
out = (out + 1) % BUFFER_SIZE;
count--;
// 通知生产者缓冲区有空间
pthread_cond_signal(¬_full);
// 解锁
pthread_mutex_unlock(&mutex);
sleep(1);
}
return NULL;
}
关键步骤解释:
- 缓冲区及变量定义:
buffer
数组作为共享缓冲区,大小为BUFFER_SIZE
。in
和out
分别是生产者和消费者的索引。count
记录缓冲区中当前的元素数量。
- 同步变量初始化:
pthread_mutex_t mutex
用于保护共享资源,避免竞态条件。pthread_cond_t not_full
条件变量用于通知生产者缓冲区未满。pthread_cond_t not_empty
条件变量用于通知消费者缓冲区非空。
- 生产者函数:
pthread_mutex_lock(&mutex)
加锁,保护共享资源。while (count == BUFFER_SIZE)
循环检查缓冲区是否已满,避免虚假唤醒。若满则调用pthread_cond_wait(¬_full, &mutex)
等待,同时释放锁。- 生产数据并更新
in
和count
。 pthread_cond_signal(¬_empty)
通知消费者缓冲区有数据。pthread_mutex_unlock(&mutex)
解锁。
- 消费者函数:
pthread_mutex_lock(&mutex)
加锁,保护共享资源。while (count == 0)
循环检查缓冲区是否为空,避免虚假唤醒。若空则调用pthread_cond_wait(¬_empty, &mutex)
等待,同时释放锁。- 消费数据并更新
out
和count
。 pthread_cond_signal(¬_full)
通知生产者缓冲区有空间。pthread_mutex_unlock(&mutex)
解锁。
这样可以有效地实现一个在多线程环境下的生产者 - 消费者模型,并通过避免虚假唤醒和合理的同步机制优化提高整体效率。在实际使用中,可以根据具体需求进一步调整和扩展代码。