空的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循环不检查条件的主要内容,如果未能解决你的问题,请参考以下文章