Linux多线程服务端编程(muduo):条件变量的使用原则以及(spurious wakeup)虚假唤醒

条件变量的使用方式:

对于wair端:

(1)必须与mutex一起使用,该布尔表达式的读写受此mutex保护。

(2)在mutex已上锁的时候才能调用wait()。

(3)把判断布尔条件和wait()放到while循环中。

// wait端
pthread_mutex_lock(mtx);
while(deque.empty())            //(这里是为了防止虚假唤醒)
    pthread_cond_wait(...);
deque.pop_front();
pthread_mutex_unlock(mtx);
 

对于singal/broadcast端:

(1)不一定要在mutex已上锁的情况下调用signal(理论上)

(2)在signal之前一般要修改布尔表达式

(3)修改布尔表达式通常要用mutex保护(至少用作full memory barrier)

(4)注意区分signal和broadcast:“broadcast通常用于表明状态变化,signal通常用于表示资源可用”

// signal端
pthread_mutex_lock(mtx);
deque.push_back(x);
pthread_cond_signal(...);
pthread_mutex_unlock(mtx);

条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制。典型的场景包括生产者-消费者模型,线程池实现等。 
对条件变量的使用包括两个动作: 
1) 线程等待某个条件, 条件为真则继续执行,条件为假则将自己挂起(避免busy wait,节省CPU资源); 
2) 线程执行某些处理之后,条件成立;则通知等待该条件的线程继续执行。 
3) 为了防止race-condition,条件变量总是和互斥锁变量mutex结合在一起使用。 
一般的编程模式: 

var mutex;  
var cond;  
var something;  
  
Thread1: (等待线程)  
lock(mutex);  
while( something not true ){  
    condition_wait( cond, mutex);  
}  
do(something);  
unlock(mutex);  
  
//============================  
  
Thread2: (解锁线程)  
  
do(something);  
....  
something = true;  
  
unlock(mutex);  
condition_signal(cond);  

函数说明: 
(1) Condition_wait():调用时当前线程立即进入睡眠状态,同时互斥变量mutex解锁(这两步操作是原子的,不可分割),以便其它线程能进入临界区修改变量。 
(2) Condition_signal(): 线程调用此函数后,除了当前线程继续往下执行以外; 操作系统同时做如下动作:从condition_wait()中进入睡眠的线程中选一个线程唤醒, 同时被唤醒的线程试图锁(lock)住互斥量mutex, 当成功锁住后,线程就从condition_wait()中成功返回了。 

.虚假唤醒(spurious wakeup)

在采用条件等待时,我们使用的是 

while(条件不满足){  
   condition_wait(cond, mutex);  
}  
而不是:  
If( 条件不满足 ){  
   Condition_wait(cond,mutex);  
}   

这是因为可能会存在虚假唤醒”spurious wakeup”的情况。 
也就是说,即使没有线程调用condition_signal, 原先调用condition_wait的函数也可能会返回。此时线程被唤醒了,但是条件并不满足,这个时候如果不对条件进行检查而往下执行,就可能会导致后续的处理出现错误。 
虚假唤醒在linux的多处理器系统中/在程序接收到信号时可能回发生。在Windows系统和JAVA虚拟机上也存在。在系统设计时应该可以避免虚假唤醒,但是这会影响条件变量的执行效率,而既然通过while循环就能避免虚假唤醒造成的错误,因此程序的逻辑就变成了while循环的情况。 
注意:即使是虚假唤醒的情况,线程也是在成功锁住mutex后才能从condition_wait()中返回。即使存在多个线程被虚假唤醒,但是也只能是一个线程一个线程的顺序执行,也即:lock(mutex)   检查/处理  condition_wai()或者unlock(mutex)来解锁. 

猜你喜欢

转载自blog.csdn.net/ypshowm/article/details/89356062