面试题答案
一键面试设计方案
-
数据结构定义:
- 定义共享缓冲区数组
buffer
,每个缓冲区可存放一个数据项。 - 定义一个数组
buffer_status
来记录每个缓冲区的状态(是否为空)。 - 定义互斥锁
mutex
用于保护共享资源(如buffer
和buffer_status
)的访问。 - 定义条件变量
empty
用于表示缓冲区有空闲位置,full
用于表示缓冲区有数据可读。 - 定义信号量
semaphore
用于限制同时访问共享缓冲区的线程数量,防止过多线程同时操作导致竞争。
- 定义共享缓冲区数组
-
生产者线程:
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; }
-
消费者线程:
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; }
可能出现死锁的情况及避免方法
-
死锁情况分析:
- 情况一:资源分配不当:如果没有信号量
semaphore
限制并发访问,可能会出现大量生产者和消费者线程同时竞争共享缓冲区,导致每个线程都占有部分资源(如互斥锁),但又在等待其他线程释放资源,从而形成死锁。 - 情况二:条件变量等待问题:如果在
pthread_cond_wait
时没有正确处理,比如没有在等待前获取互斥锁,或者在等待返回后没有重新获取互斥锁,可能会导致线程在等待过程中被其他线程修改共享资源状态,从而错过条件变量的信号,造成死锁。
- 情况一:资源分配不当:如果没有信号量
-
避免死锁方法:
- 使用信号量限制并发:通过信号量
semaphore
限制同时访问共享缓冲区的线程数量,避免过多线程竞争资源,从而防止因资源分配不当导致的死锁。 - 正确使用条件变量:在
pthread_cond_wait
前必须获取互斥锁,并且在pthread_cond_wait
返回后重新获取互斥锁,确保在等待过程中共享资源状态不会被非法修改,避免错过条件变量信号导致的死锁。同时,在条件变量等待的循环中检查条件,防止虚假唤醒。
- 使用信号量限制并发:通过信号量