引用手册页:
当使用条件变量时,总是有一个布尔 predicate 涉及与每个条件等待相关联的共享变量,如果线程应该继续,则该条件等待为真。()或pthread_cond_wait的值()函数可能会发生。由于从pthread_cond_timedwait返回()或pthread_cond_wait()并不暗示有关此 predicate 值的任何内容,则应在返回此类值时重新计算 predicate 。
因此,即使没有发出信号,pthread_cond_wait
也可以返回。这看起来很糟糕。2这就像一个函数随机返回错误的值,或者在它实际到达一个正确的return语句之前随机返回。3这看起来是一个主要的bug。但是,他们选择在手册页中记录这个问题而不是修复它的事实似乎表明,pthread_cond_wait
最终被唤醒是有正当理由的很可能,它的运作方式中有某种内在的东西使它无法避免。问题是是什么。
- 为什么 *
pthread_cond_wait
会错误地返回?为什么它不能保证只有在收到正确的信号时才会醒来?有人能解释它错误行为的原因吗?
5条答案
按热度按时间2ic8powd1#
“伪唤醒”至少有两种含义:
pthread_call_signal
或pthread_cond_broadcast
,在pthread_cond_wait
中封锁的执行绪也可以从呼叫传回。pthread_cond_signal
或pthread_cond_broadcast
,pthread_cond_wait
中阻塞的线程返回,但在重新获取互斥锁后,发现基础 predicate 不再为真。但是,即使条件变量实现不允许前一种情况,后一种情况也可能发生。
pthread_cond_wait
,并阻塞等待信号/广播的调用。因此,由于您已经始终需要检查循环下的 predicate ,因此,如果底层条件变量可以有其他类型的伪唤醒,也没有什么区别。
u5i3ibmn2#
下面的解释由大卫·R·布滕霍夫在"Programming with POSIX Threads"(p. 80)中给出:
伪唤醒听起来可能很奇怪,但在某些多处理器系统上,使条件唤醒完全可预测可能会大大降低所有条件变量操作的速度。
在下面的comp.programming.threads discussion中,他详细阐述了设计背后的思想:
yhived7q3#
pthread_cond_signal中的“通过条件信号进行多次唤醒”一节提供了pthread_cond_wait和pthread_cond_signal的实现示例,其中涉及伪唤醒。
esbemjvw4#
虽然我认为在设计时没有考虑到这一点,但这里有一个实际的技术原因:结合线程取消,在某些情况下,选择“伪”唤醒可能是绝对必要的,至少除非您愿意对可能的实现策略施加非常非常强的约束。
关键问题是,如果线程在
pthread_cond_wait
中阻塞时执行取消操作,副作用必须是好像它没有消耗条件变量上的任何信号。(且高度约束),以确保在开始执行取消操作时尚未使用信号,并且在此阶段可能无法将信号“重新发布”到条件变量,因为您可能处于pthread_cond_signal
的调用者已经被证明销毁了condvar并释放了它所驻留的内存的情况。允许伪尾流给你一个简单的出路。如果你可能已经消耗了一个信号,而不是在它到达时继续对取消采取行动,而在一个条件变量上被阻止(或者如果你想偷懒,不管怎样),你可以声明一个伪唤醒已经发生,并成功返回。这完全不会干扰取消操作,因为正确的调用程序在下次循环并再次调用
pthread_cond_wait
时将简单地对未决取消进行操作。tquggr8v5#
我认为伪唤醒的主要原因是**
EINTR
**。EINTR中断的函数调用(POSIX.1-2001);参见信号(7)。
来源:https://man7.org/linux/man-pages/man3/errno.3.html,另请参阅
基本上,由
pthread_cond_wait()
(例如futex(2)
)调用的系统调用可能会返回EINTR
。如果系统调用在内核中被阻塞,并且被POSIX信号中断,通常会发生这种情况(请参阅signal(7)
)。请参阅www.example.com上的"What is the rationale behind EINTR?"unix.stackexchange.com原因是什么如果系统调用在POSIX信号被传递并由系统调用发出线程处理之后被中断,则(某些)操作系统返回EINTR
。我假设一旦用于实现例如
pthread_cond_wait()
的低级操作系统原语返回EINTR
,就存在潜在的竞争条件。pthread_cond_wait()
的实现可能不会简单地重新发出系统调用,因为该条件现在可能成立。如果在EINTR
之后没有重新评估该条件,那么这很容易导致死锁,在死锁中应用程序没有进一步的进展。