2025年c++11条件变量虚假唤醒(c++11条件变量 使用)

c++11条件变量虚假唤醒(c++11条件变量 使用)接下来 给出 pthread cond wait 和 pthread cond signal 的伪代码 参考 man pthread cond signal 语句后面的编号代表时间上的执行顺序 对于一般情况 wait 完成进入等待队列的情况比较简单 就不考虑了 我们考虑在释放互斥锁后 进入 wait 等待队列前的情况 假设只有两个线程 A 和 B 线程 A 执行完语句 2 后正在尝试进入等待队列



接下来,给出 pthread_cond_wait 和 pthread_cond_signal 的伪代码(参考man pthread_cond_signal)。语句后面的编号代表时间上的执行顺序。

对于一般情况,wait 完成进入等待队列的情况比较简单,就不考虑了。我们考虑在释放互斥锁后,进入 wait 等待队列前的情况:

假设只有两个线程 A 和 B

线程 A 执行完语句 2 后正在尝试进入等待队列(已经解锁但是尚未阻塞),即期望执行语句 10 以及后面的进入等待队列. 同时线程 B 正在执行 pthread_cond_signal 中的语句 3 到语句 9. 此时等待队列为空,所以 if (cond->waiter) 条件不成立。

另外条件也发生了改变(),线程 B 完成了 pthread_signal 返回后,线程 A 执行语句 10,因为条件已经成立,所以线程 A 不会进入等待队列直接返回。宏观上看起来,好像就是从“等待队列”中被唤醒一样。

如果你还记得在上一篇条件变量中的叙述:

pthread_cond_wait 被分解成了三步,其中 a1 和 a2 是一次执行完的。这两个步骤是原子的。

而实际上,pthread_cond_wait 的实现应该像本文上面的伪代码, 即阻塞不是必须的,能给人一种错觉就够了。

再次回顾一下前文所述:

如果线程 A 在释放锁后(语句 a1),执行语句 a2 的即将要阻塞的时候,线程 B 此时调用 pthread_cond_signal 或者 pthread_cond_broadcast ,感觉就好像即将要被阻塞的线程 A 已经阻塞过一样。

现在你应该理解了所谓的“原子”是怎么做的了吧。

英文术语叫 spurious wakeup

在前一篇文章中说,pthread_cond_signal 可以唤醒队列中的一个线程,而实际上,它也可能唤醒不止一个线程。

man 手册做此解释::

在多核系统中,要避免 pthread_cond_signal 唤醒超过一个以上的线程,似乎是不可能的。

继续使用前面使用的伪代码。

假设只有三个线程 A 、B 和 C

线程 A 执行完语句 2 后正在尝试进入等待队列(已经解锁但是尚未阻塞),即期望执行语句 10 以及后面的进入等待队列. 同时线程 B 正在执行 pthread_cond_signal 中的语句 3 到语句 9. 另一方面,线程 C 正处于等待队列中。

和第 1 节中不一样的是,语句 5  成立,因为队列中有线程 C。因此 pthread_cond_signal 会唤醒线程 C。而线程 A 也会因为 直接执行语句13. 记住,此时的 A 是唤醒状态,不是位于等待队列中。

一旦线程 C 释放锁后,线程 A 就返回,然而此时,条件可能已经不成立(比如条件被程 C 更改),故出现虚假唤醒的状态。

实际上在上一篇的实验中已经给出了解决方案,即即使 pthread_cond_signal 已经返回,也不意味着条件一定成立,代码中使用了循环  反复测试。

切记,这里不要使用 ,而是 !!! 目的在于防止虚假唤醒——spurious wakeup.

  • 深入理解条件变量的实现
  • 什么是虚拟唤醒
  • 如何避免虚假唤醒
编程小号
上一篇 2025-01-27 20:21
下一篇 2025-03-15 22:21

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ri-ji/64971.html