面试题答案
一键面试虚假唤醒常见场景
- 多线程竞争资源:当多个线程同时等待同一个条件变量时,系统可能会因为调度等原因,在条件未满足的情况下唤醒其中一个或多个线程。例如,在生产者 - 消费者模型中,多个消费者线程等待队列中有数据的条件变量,当生产者向队列中添加数据并唤醒等待的消费者线程时,可能会有多个消费者线程被唤醒,但此时队列中可能只有一条数据,多余被唤醒的消费者线程即为虚假唤醒。
- 信号干扰:Linux系统中,线程可能会收到一些信号,这些信号可能会导致条件变量的虚假唤醒。比如,一个线程正在等待条件变量,同时收到了一个异步信号,在处理信号后,线程可能会从等待条件变量的状态中被唤醒,即使条件并没有真正满足。
处理虚假唤醒的代码方式
使用循环检查条件变量的条件,确保唤醒后条件确实满足。当条件变量被唤醒时,不直接认为条件已经满足,而是再次检查条件。如果条件不满足,则继续等待。
示例代码
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int ready = 0;
void* thread_function(void* arg) {
pthread_mutex_lock(&mutex);
// 使用循环检查条件,防止虚假唤醒
while (!ready) {
printf("线程等待条件变量...\n");
pthread_cond_wait(&cond, &mutex);
}
printf("线程被唤醒,条件已满足\n");
pthread_mutex_unlock(&mutex);
return NULL;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, thread_function, NULL);
sleep(2); // 主线程睡眠2秒模拟其他工作
pthread_mutex_lock(&mutex);
ready = 1;
printf("主线程设置条件为真,并唤醒等待的线程\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
pthread_join(tid, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
在上述代码中,thread_function
函数中的while (!ready)
循环用于防止虚假唤醒。当pthread_cond_wait
被唤醒时,会先检查ready
条件,如果不满足则继续等待。主线程在设置ready
为1
后,通过pthread_cond_signal
唤醒等待的线程。