面试题答案
一键面试条件变量的基础使用场景
条件变量通常用于线程间的同步,当某个条件满足时,一个或多个线程会被唤醒。它依赖于一个互斥锁,一般用于等待某个特定条件发生的场景。例如,在一个线程池任务处理场景中,工作线程等待任务队列中有新任务(条件),当有新任务添加到队列时(条件满足),等待的工作线程被唤醒去处理任务。
信号量的基础使用场景
信号量用于控制对共享资源的访问数量。它通过一个计数器来管理,当计数器大于0时,线程可以获取信号量(计数器减1)来访问资源,访问完后释放信号量(计数器加1)。常用于控制对有限资源的并发访问。比如,在数据库连接池场景中,信号量可以用来控制同时获取连接的线程数量,防止过多线程同时获取连接导致资源耗尽。
在生产者 - 消费者模型中条件变量的应用
- 数据结构准备:假设有一个共享缓冲区用于生产者和消费者之间的数据传递,同时有一个互斥锁
mutex
用于保护对缓冲区的访问,一个条件变量cond
用于通知消费者缓冲区有数据。
#include <pthread.h>
#include <stdio.h>
#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
- 生产者函数:生产者在向缓冲区写入数据前先获取互斥锁,当缓冲区满时等待条件变量
cond
,有空间时写入数据并通知消费者。
void *producer(void *arg) {
int item = 1;
while (1) {
pthread_mutex_lock(&mutex);
while ((in + 1) % BUFFER_SIZE == out) {
pthread_cond_wait(&cond, &mutex);
}
buffer[in] = item++;
printf("Produced: %d\n", buffer[in]);
in = (in + 1) % BUFFER_SIZE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
- 消费者函数:消费者在从缓冲区读取数据前获取互斥锁,当缓冲区空时等待条件变量
cond
,有数据时读取数据并通知生产者。
void *consumer(void *arg) {
while (1) {
pthread_mutex_lock(&mutex);
while (in == out) {
pthread_cond_wait(&cond, &mutex);
}
int item = buffer[out];
printf("Consumed: %d\n", item);
out = (out + 1) % BUFFER_SIZE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
在生产者 - 消费者模型中信号量的应用
- 数据结构准备:同样有共享缓冲区,用两个信号量
empty
表示缓冲区的空闲槽位数量,full
表示缓冲区已占用槽位数量,还有一个互斥锁mutex
保护对缓冲区的访问。
#include <semaphore.h>
#include <pthread.h>
#include <stdio.h>
#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
sem_t empty;
sem_t full;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- 生产者函数:生产者先获取
empty
信号量表示有空闲槽位,获取互斥锁后写入数据,然后释放full
信号量表示有数据可供消费。
void *producer(void *arg) {
int item = 1;
while (1) {
sem_wait(&empty);
pthread_mutex_lock(&mutex);
buffer[in] = item++;
printf("Produced: %d\n", buffer[in]);
in = (in + 1) % BUFFER_SIZE;
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
return NULL;
}
- 消费者函数:消费者先获取
full
信号量表示有数据,获取互斥锁后读取数据,然后释放empty
信号量表示有空闲槽位。
void *consumer(void *arg) {
while (1) {
sem_wait(&full);
pthread_mutex_lock(&mutex);
int item = buffer[out];
printf("Consumed: %d\n", item);
out = (out + 1) % BUFFER_SIZE;
pthread_mutex_unlock(&mutex);
sem_post(&empty);
}
return NULL;
}
通过上述方式,条件变量和信号量在生产者 - 消费者模型中分别通过不同机制保证了数据一致性和线程协作。