虚假的唤醒真的发生了吗?
看到各种与locking有关的问题和(几乎)总是find“虚假唤醒”术语的循环1我想知道,有没有人经历过这种唤醒(假设一个像样的硬件/软件环境)?
我知道“虚假”一词的含义没有明显的原因,但是这种事件的原因是什么呢?
( 1注:我不是在质疑循环练习。)
编辑:帮手问题(对于喜欢代码示例的人):
如果我有以下程序,我运行它:
public class Spurious { public static void main(String[] args) { Lock lock = new ReentrantLock(); Condition cond = lock.newCondition(); lock.lock(); try { try { cond.await(); System.out.println("Spurious wakeup!"); } catch (InterruptedException ex) { System.out.println("Just a regular interrupt."); } } finally { lock.unlock(); } } }
我可以做些什么来唤醒这个await
,而不会永远等待随机事件呢?
关于虚假唤醒的维基百科文章有这个珍闻:
Linux中的
pthread_cond_wait()
函数是使用futex
系统调用实现的。 当进程接收到一个信号时,Linux上的每个阻塞系统调用会突然返回EINTR
。 …pthread_cond_wait()
无法重新启动等待,因为它可能会在futex
系统调用之外的一小段时间内错过真正的唤醒。 这个竞争条件只能由调用者检查一个不variables来避免。 POSIX信号将因此产生虚假的唤醒。
总结 :如果一个Linux进程发出信号,它的等待线程将会每个都享受一个很好的,热的虚假唤醒 。
我买它。 这是一个容易吞咽的药丸,而不是通常模糊的“这是为了performance”的原因。
我有一个生产系统,performance出这种行为。 线程等待队列中有消息的信号。 在繁忙时期,高达20%的唤醒是虚假的(即,当它醒来时,队列中没有任何东西)。 这个线程是消息的唯一消费者。 它运行在一个Linux SLES-10 8处理器盒子上,并使用GCC 4.1.2构build。 这些消息来自外部来源,并且是asynchronous处理的,因为如果我的系统没有足够快地读取它们,就会出现问题。
要回答这个问题 – 是的! 它确实发生了。尽pipeWiki文章提到了关于虚假唤醒的一个很好的解决scheme,但我所遇到的一个很好的解释如下 –
试想一下…就像任何代码一样,由于底层硬件/软件发生exception,线程调度器可能会经历暂时的中断。 当然,应该注意这种情况的发生尽可能less,但是由于不存在100%健壮的软件,所以假定这种情况可能发生,并在情况下如果调度器检测到这种情况(例如,通过观察失踪的心跳)。
现在,调度程序如何恢复,考虑到在停电期间它可能会错过一些信号来通知等待线程? 如果调度程序什么都不做,提到“不幸”的线程就会挂起,永远等待 – 为了避免这种情况,调度程序只会发送一个信号给所有正在等待的线程。
这使得有必要build立一个“等待线程可以无故通知”的“合同”。 确切地说,会有一个原因 – 调度程序停电 – 但是由于线程的devise(有充分的理由)忘记了调度程序的内部实现细节,这个原因可能更好地performance为“虚假”。
我从Source阅读这个答案,发现它足够合理。 还读
Java中的虚假唤醒以及如何避免它们 。
Cameron Purdy写了一篇博文 ,回想起被虚惊的问题所打击。 所以是的,它发生了
我猜是因为Java部署的一些平台的限制,这是规范(作为一种可能性)? 虽然我可能是错的!
只是添加这个。 是的,它发生了,我花了三天时间在24核心机器(JDK 6)上寻找multithreading问题的原因。 10个处决中有4个没有任何模式。 这从来没有发生在2核心或8核心上。
研究了一些在线资料,这不是一个Java问题,而是一个罕见的,但预期的行为。