对于原始人,我认为这是必要的。 即使对于非原始数据,例如数组,我认为这也是必要的。
没有不稳定:
int d[2];
主题1:
while (d[1] > 0) modify(d[0]);
主题2:
while (d[0] > 0) modify(d[1]);
我担心编译器会在没有volatile的情况下更改我的代码。 while(true)modify();
所以我在'int d [2]'之前放了volatile; 但是我觉得有些奇怪的东西都是用挥发物装饰的。
答案 0 :(得分:5)
不,这不是挥发性的用途。易失性用于可能在程序之外更改的变量 - 例如。内存映射设备,图形内存等。
没有必要仅仅因为程序是多线程的 - 既不是原始类型也不是数组。
答案 1 :(得分:3)
没有。易失性是指在没有编译器知道的情况下可以读取和/或写入的变量。虽然另一个更改变量的线程可能看起来像这种情况,但volatile
对于多线程编程来说还不够,也不是实际需要。
除非你自己编写同步原语,否则这样做比看起来更难。而且似乎很难......
有关详细信息,您可以在Volatile considered harmful阅读有关此问题的Linux见解。这篇文章是针对C而不是C ++,但适用相同的原则。
答案 2 :(得分:-2)
在这种情况下,有两个线程是“修改彼此的数据”,这确实需要编译器知道数据正被另一个线程修改。有几种解决方案可以解决这个问题,volatile
将告诉编译器它不能在第一次读取时将值存储在寄存器中,但是存在问题....
最重要的是,volatile
无法解决d[1] > 0
被更改时精确检测“边缘”的问题,因为使用volatile
,所有您可以保证编译器不会删除变量的读取。在具有多个内核的系统中,线程1中的新数据到达线程2之间可能存在“延迟”。意味着d[0]
可能被修改的次数超过预期,因为循环运行了几个额外的周期。在极端情况下,例如ARM处理器的某些型号,循环可能或多或少地无限运行,因为处理器(核心)将需要刷新缓存线,并且除非其他东西使用相同的缓存,否则不会在没有干预的情况下发生 - 线。在一个不繁忙的系统中,这可能需要你已经或更长时间......;)
所以,我不同意多线程环境中不需要volatile
,但我同意这不是整个解决方案。如果检测值已更改,则需要std::atomic
和其他类似结构以确保正确性。“立即”需要代码才能正常工作。
跨线程共享数据是一件困难的事情,需要仔细规划和理解才能使其正常工作。我知道上面的代码可能只是一个简化的例子,但是如果modify(d[1])
很简单,那么共享数据就会非常糟糕,并且很可能它会像单个线程一样运行得比单个线程更慢 - 线程循环,因为一个处理器的每个高速缓存行写入将强制刷新另一个处理器上的高速缓存行。因此,它就像在繁忙的曼哈顿交通中驾驶法拉利跑车 - 不是非常节能,也不比简单的解决方案快。