空的while循环不检查条件

Posted

技术标签:

【中文标题】空的while循环不检查条件【英文标题】:Empty while loop not checking condition 【发布时间】:2011-03-31 03:58:57 【问题描述】:

在一个多线程的 C++ 程序中,我在一个线程中运行的等效项:

while(obj->member)   // waiting for obj->member to be set to false in another thread

在另一个线程中,obj->member 设置为 false。然而,即使它设置为 false,循环也不会中断。如果我把它改成这样:

while(obj->member)  Sleep(1) 

当 obj->member 在另一个线程中设置为 false 时,它​​按预期工作并中断。 为什么会这样?

【问题讨论】:

请不要使用忙等待 - 了解条件变量或类似的同步原语。 什么?我不知道那是什么意思。 我将支持@Arkadiy 所说的内容(如果您不知道这意味着什么,则需要在编写更多多线程代码之前进行大量阅读)。除了繁忙的等待(这只是一种糟糕的形式)之外,您的代码也不是线程安全的。但是,考虑到您在在这种确切情况下所做的事情的简单性,我认为您不会在任何常见的 CPU 架构上遇到问题。 【参考方案1】:

尝试制作会员volatile。这将强制它在每次使用时从内存中获取,而不是从 CPU 寄存器中获取(这是编译器可能优化它的方式。)

【讨论】:

【参考方案2】:

Obj 必须声明为 volatile。这告诉编译器它的值可能会被其他线程改变。

当您添加Sleep 时,编译器知道其他线程正在工作,并假定它可能会改变。

【讨论】:

编译器从volatile 关键字中知道,而不是Sleep 的存在。 也许吧,但我很怀疑。 Sleep 的存在没有理由表明进程中有其他线程。即使在单线程应用程序中,在紧密循环中添加Sleep 或其他一些让步操作也很常见。我认为 OP 的不屈不挠的循环更有可能只是让另一个线程饿死,以至于它永远无法设置标志。【参考方案3】:

它起作用的事实大多是偶然的。如果你想可靠地做这样的事情,你只需要使用某种操作系统提供的 IPC 机制,可能使用Boost Interprocess(例如,互斥锁或信号量)来提供更便携的前端。

volatile,虽然经常被提出来作为此类问题的解决方案,但既没有必要也不够充分。它可能会损害性能(很多),但仍然不足以使线程正常工作。如果您正在为 .NET 编程,Microsoft已经定义了它的 volatile 版本以提供(至少某种程度的)线程安全。否则(在真正的 C 或 C++ 中),它几乎没有实际用途,并且可能造成相当大的危害。

我还应该提到,这是一个漫长的方式,从第一次犯这个错误开始。很久以前,不亚于 Andre Alexandrescu 的权威在 Doctor Dobbs 上写了一篇关于使用volatile 进行线程的相当重要的文章。他已经意识到自己错了,但是(在很大程度上)损害已经造成——尤其是因为volatile 非常接近于做正确的事情,以至于很容易将其误认为是正确/有用的线程.

【讨论】:

【参考方案4】:

更好的方法是使用事件而不是布尔值。对于一个事件,你可以在不使用任何 CPU 的情况下等待它,并且你不必休眠或使用 volitile。

【讨论】:

【参考方案5】:

也许您的线程库在创建线程时制作了对象的副本,并且除非声明为静态成员,否则该成员实际上并未在线程之间共享。

【讨论】:

以上是关于空的while循环不检查条件的主要内容,如果未能解决你的问题,请参考以下文章

C----循环

检查while循环内的正则表达式条件(shell)

python if 判断 while 循环 for 循环

for 循环与while循环的区别

JavaScript流程语句

do...while 语句