面试题答案
一键面试条件变量与互斥锁协作原理
- 互斥锁(Mutex):
- 互斥锁用于保护共享资源,确保同一时间只有一个线程能够访问共享资源,避免数据竞争。它是一种二元信号量,只有两种状态:锁定(locked)和解锁(unlocked)。
- 当一个线程获取到互斥锁(将其状态设为锁定),其他线程试图获取该互斥锁时会被阻塞,直到持有锁的线程释放锁(将其状态设为解锁)。
- 条件变量(Condition Variable):
- 条件变量用于线程间的同步,它允许线程等待某个条件满足。条件变量本身并不保护共享资源,需要与互斥锁配合使用。
- 一个线程可以在条件变量上等待,同时释放与之关联的互斥锁,进入睡眠状态。当另一个线程改变了共享资源的状态,使得等待的条件满足时,它可以唤醒在该条件变量上等待的线程。被唤醒的线程会重新获取互斥锁,然后继续执行。
生产者 - 消费者模型下的应用
- 场景描述:
- 生产者线程不断生成数据并放入共享缓冲区,消费者线程从共享缓冲区取出数据进行处理。共享缓冲区的大小有限,需要避免生产者在缓冲区满时继续写入,以及消费者在缓冲区空时读取。
- 核心代码逻辑(以Linux pthread库为例):
#include <pthread.h>
#include <stdio.h>
#include <stdlib.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(¬_full, &mutex);
}
buffer[in] = i;
printf("Produced: %d\n", buffer[in]);
in = (in + 1) % BUFFER_SIZE;
count++;
pthread_cond_signal(¬_empty);
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
// 消费者线程函数
void* consumer(void* arg) {
int i;
for (i = 0; i < 10; i++) {
pthread_mutex_lock(&mutex);
while (count == 0) {
pthread_cond_wait(¬_empty, &mutex);
}
int data = buffer[out];
printf("Consumed: %d\n", data);
out = (out + 1) % BUFFER_SIZE;
count--;
pthread_cond_signal(¬_full);
pthread_mutex_unlock(&mutex);
}
pthread_exit(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(¬_full);
pthread_cond_destroy(¬_empty);
return 0;
}
在上述代码中:
- 互斥锁
mutex
:保护共享缓冲区buffer
以及相关变量in
、out
、count
,确保在访问这些共享资源时的互斥性。 - 条件变量
not_full
:当缓冲区满时(count == BUFFER_SIZE
),生产者线程通过pthread_cond_wait
等待该条件变量,同时释放互斥锁mutex
。当消费者从缓冲区取出数据后,通过pthread_cond_signal
唤醒等待在not_full
上的生产者线程。 - 条件变量
not_empty
:当缓冲区空时(count == 0
),消费者线程通过pthread_cond_wait
等待该条件变量,同时释放互斥锁mutex
。当生产者向缓冲区写入数据后,通过pthread_cond_signal
唤醒等待在not_empty
上的消费者线程。