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