我知道volatile
通知编译器可能会更改值,但为了完成此功能,编译器是否需要引入内存栅栏才能使其工作?
根据我的理解,易失性对象的操作顺序不能重新排序,必须保留.这似乎暗示一些内存栅栏是必要的,并且没有真正解决方法.我说的是对的吗?
在这个相关问题上有一个有趣的讨论
...对于不同的volatile变量的访问不能由编译器重新排序,只要它们出现在单独的完整表达式中......对于线程安全而言volatile是无用的,但不是由于他给出的原因.这不是因为编译器可能会重新排序对易失性对象的访问,而是因为CPU可能会重新排序它们.原子操作和内存屏障阻止编译器和CPU重新排序
...从C++标准的角度来看,编译器执行某些操作与编译器发出导致硬件执行某些操作的指令之间没有区别.如果CPU可能重新排序对volatiles的访问,则标准不要求保留其订单....
... C++标准没有对重新排序有什么区别.你不能争辩说CPU可以重新排序它们没有可观察到的影响,所以没关系--C++标准将它们的顺序定义为可观察的.如果编译器生成的代码使平台能够满足标准要求,则编译器在平台上符合C++标准.如果标准要求对挥发物的访问不能重新排序,则重新排序它们的平台不符合要求....
我的观点是,如果C++标准禁止编译器重新排序对不同易失性的访问,理论上这种访问的顺序是程序可观察行为的一部分,那么它还要求编译器发出禁止CPU执行的代码所以.该标准没有区分编译器的作用以及编译器生成的代码使CPU执行的操作.
这确实产生了两个问题:它们中的任何一个是"正确的"吗?实际的实现到底做了什么?
任何通常遵循的标准(ISO C或C++,或任何POSIX/SUS规范)是否有任何保证,由多个线程访问的变量(可能标记为volatile)(未被互斥锁保护)将最终保持一致如果分配给?
要提供一个特定示例,请考虑共享变量v的两个线程,初始值为零.
线程1:v = 1
线程2:while(v == 0)yield();
线程2是否保证最终终止?或者它可以想象永远旋转,因为缓存一致性从未启动并使得赋值在线程2的缓存中可见?
我知道C和C++标准(在C++ 0x之前)完全没有关于线程或并发的说法.但我很好奇,如果C++ 0x内存模型,或pthreads,或其他任何东西,保证这一点.(显然这确实可以在Windows上运行32位x86;我想知道它是否可以依赖于某些东西,或者它是否恰好在那里工作).