在多线程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时,它按预期工作并中断 为什么它会像这样工作?
答案 0 :(得分:10)
尝试制作成员volatile
。这将强制每次使用它时从内存中取出它,而不是从CPU寄存器中取出(这是编译器可能优化它的方式。)
答案 1 :(得分:6)
Obj
必须声明为volatile
。这告诉编译器它的值可能会被其他一些线程改变。
当您添加Sleep
时,编译器知道其他线程正在运行,并假设它可能会更改。
答案 2 :(得分:4)
它的工作原理大多是偶然的。如果你想要可靠地做这样的事情,你只需要使用某种OS提供的IPC机制,可能使用Boost Interprocess(例如,互斥或信号量)来提供更便携的前端。
volatile
虽然经常被提出作为这样的问题的解决方案,但既不必要也不充分。它可能会损害性能(很多),但仍然不足以使线程正常工作。如果您正在为.NET编程,Microsoft 已定义其版本volatile
以提供(至少某种程度的)线程安全性。否则(在真正的C或C ++中),它几乎没有用,并且会造成相当大的伤害。
我还应该提到,从第一次犯这个错误开始,这是 long 方式。回想起当时,Andre Alexandrescu在Dobbs医生中写了一篇关于使用volatile
进行线程化的相当实质性的文章。他已经意识到他错了,但(在很大程度上)损害已经完成 - 特别是因为volatile
非常接近于做正确的事情,因此很容易将其误认为正确/有用在线程中。
答案 3 :(得分:2)
更好的方法是使用事件而不是bool。通过一个事件,您可以在不使用任何CPU的情况下等待,而且您不必睡觉或使用volitile。
答案 4 :(得分:0)
也许你的线程库在创建线程时正在创建对象的副本,并且除非被声明为静态,否则成员之间不会真正共享成员。