虚假唤醒

为什么条件锁会产生虚假唤醒现象(spurious wakeup)?

pthread_cond_wait()通常是通过操作系统的系统调用完成的,例如Linux是通过futex,对于这些阻塞的系统调用在进程被信号中断后,就会终止阻塞,并返回EINTR错误。对于read(),write()这些IO操作只需要再次重试即可,但是pthread_cond_wait()不能,因为在本线程拿到EINTR错误到futex重新执行的过程中,已经有其他线程通过pthread_cond_signal或者pthread_cond_broadcast()发过通知,此时当前线程很可能会错过最早的唤醒时机,所以会产生虚假唤醒。

维基上有一段话这样解释:

"This means that when you wait on a condition variable, the wait may (occasionally) return when no thread specifically broadcast or signaled that condition variable. Spurious wakeups may sound strange, but on some multiprocessor systems, making condition wakeup completely predictable might substantially slow all condition variable operations. The race conditions that cause spurious wakeups should be considered rare."

即虚假唤醒是有意为之,我理解的是为了加快线程之间的响应,减少等待时间。

所以为了配合“虚假唤醒”,我们必须在判断condition时使用while(),而不是使用if。使用if会是程序存在漏洞,例如空指针。使用while()进行判断,则“迎合”了底层的这种机制,如果条件不满足退出,则会继续wait()。

另外有的文章认为“虚假唤醒”是pthread_cond_signal可能会唤醒多于一个线程,但是只有一个线程处理了任务,其他线程的唤醒相当于白白浪费了资源。实际上这种现象更类似于惊群现象:惊群效应就是当一个fd的时间被触发时,所有等待这个fd的线程或进程都被唤醒。一般都是socket的accept()会导致惊群,很多个进程都阻塞在server socket的accept(),一旦有客户进来,所有进程的accept()都会返回,但是只有一个进程会读到数据,就是惊群,但是Linux内核实现中不会出现惊群了,只会有一个进程被唤醒。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值