互斥锁和条件变量

1.条件变量和mutex到底有什么区别?都是在没有拿锁的情况下阻塞,拿到锁了解除阻塞。那为什么还要用条件变量呢?

2.pthread_cond_broadcast和pthread_cond_signal。既然阻塞的线程被唤醒了之后第一件事就是拿锁,那么即使是broadcast,也会竞争锁,导致只有一个线程能继续,那么signal和broadcast有什么区别吗?

3.pthread_cond_wait()前要加一个while循环来判断条件是否为假的原因?
 
1、考虑一个简单的生产者和消费者的模型:由一个 int count 标识生产者的生产数量,count 由一个 mutex 上锁避免消费者和生产者同时访问。如果只使用 mutex,则消费者需要循环扫描 count 的值以及时获得变化;而如果使用 cond,则两者只需要用锁保护 cond,消费者在 pthread_cond_wait后,交出 mutex 阻塞等待,直到 cond 被激活。
 
2、signal选择一个线程唤醒,然后这个线程去干活。
broadcast只是让所有线程都从睡眠中醒来,然后一个人干活,其他人继续等在锁上。
假设A是生产者,B和C是消费者。B,C都在睡觉,A一次性向队列里加了两个东西,唤醒B和C。
B和C这时候要抢锁,假设B抢到,它从队列里取走一个,释放锁然后去干活了。这时候C获得锁,可以把另一个也取走。假如没有broadcast,C就继续睡,等B干完一个活再回来干另一个。
 

3、在多核处理器下,pthread_cond_signal可能会激活多于一个线程(阻塞在条件变量上的线程)。 

结果是,当一个线程调用pthread_cond_signal()后,多个调用pthread_cond_wait()或pthread_cond_timedwait()的线程返回。这种效应成为”虚假唤醒”(spurious wakeup) 。

虽然虚假唤醒在pthread_cond_wait函数中可以解决,为了发生概率很低的情况而降低边缘条件(fringe condition)效率是不值得的,纠正这个问题会降低对所有基于它的所有更高级的同步操作的并发度。所以pthread_cond_wait的实现上没有去解决它。

所以通常的标准解决办法是这样的:

将条件的判断从if 改为while

pthread_cond_wait中的while()不仅仅在等待条件变量检查条件变量,实际上在等待条件变量也检查条件变量。

这样对condition进行多做一次判断,即可避免“虚假唤醒”.

这就是为什么在pthread_cond_wait()前要加一个while循环来判断条件是否为假的原因。

有意思的是这个问题也存在几乎所有地方,包括: linux 条件等待的描述, POSIX Threads的描述, window API(condition variable), java等等。

posted @ 2014-03-01 20:54  YEQ  阅读(457)  评论(0编辑  收藏  举报