在本文中:http://www.drdobbs.com/parallel/易失性-vs-易失性/212701484?pgno=2 http://www.drdobbs.com/parallel/volatile-vs-volatile/212701484?pgno=2说,我们不能做任何优化volatile
,甚至例如(其中:volatile int& v = *(address);
):
v = 1; // C: write to v
local = v; // D: read from v
无法对此进行优化:
v = 1; // C: write to v
local = 1; // D: read from v // but it can be done for std::atomic<>
这是无法完成的,因为第一行和第二行之间可能v
值可以改变为硬件设备(不是无法实现缓存一致性的 CPU:网络适配器、GPU、FPGA 等...)(顺序/并发),映射到该内存位置。但只有当v
不能缓存在 CPU 缓存 L1/2/3 中,因为对于通常情况(非volatile
)第一行和第二行之间的变量时间太小,可能会触发缓存。
Does volatile
限定符保证不缓存该内存位置?
ANSWER:
- No,
volatile
不保证不缓存对于这个内存位置,C/C++ 标准或中没有任何关于此的内容编译器手册 http://gcc.gnu.org/onlinedocs/gcc/Volatiles.html.
- 使用内存映射区域,当从设备内存映射到CPU内存的内存已标记为WC时 https://stackoverflow.com/a/1757198/1558037(写入合并)而不是 WB,这会取消缓存。并且不需要进行缓存刷新.
- 相反,如果CPU内存映射到设备内存,那么顺便说一句,位于CPU晶体上的控制器PCIE正在监听从该设备通过DMA的数据,并更新(无效)CPU缓存L3。在这种情况下,如果设备上的可执行代码使用
volatile
尝试执行相同的两行,它还会取消设备的高速缓存(例如在高速缓存 GPU-L2 中)。和不需要进行 GPU 缓存刷新,也不需要进行 CPU 缓存刷新 https://stackoverflow.com/questions/12027849/how-can-i-read-from-the-pinned-lock-page-ram-and-not-from-the-cpu-cache-use/12028433#12028433。另外对于CPU可能需要使用std::atomic_thread_fence(std::memory_order_seq_cst);
如果 L3 缓存 (LLC) 与 PCIE 上的 DMA 一致,但 L1/L2 不是 http://en.wikipedia.org/wiki/Direct_memory_access#Cache_coherency。对于 nVidia CUDA,我们可以使用:void __threadfence_system(); http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#memory-fence-functions
- We 需要刷新 DMA 控制器缓存,当发送未对齐的数据时:(WDK: KeFlushIoBuffers(), FlushAdapterBuffers()) http://msdn.microsoft.com/en-us/library/windows/hardware/ff545924%28v=vs.110%29.aspx
- 此外,我们可以通过 MTRR 寄存器将任何内存区域标记为未缓存,如 WC 标记。
volatile
确保变量不会被“缓存”在CPU寄存器中。 CPU 缓存对程序员是透明的,如果另一个 CPU 写入另一个 CPU 缓存映射的内存,则第二个 CPU 的缓存将失效,因此它将在下次访问时再次从内存重新加载值。
一些有关缓存一致性 http://en.wikipedia.org/wiki/Cache_coherence
至于外部存储器写入(通过 DMA 或另一个独立于 CPU 的通道),您可能需要手动刷新缓存(请参阅this https://stackoverflow.com/questions/1756825/cpu-cache-flush所以问题)
C 标准§6.7.3 7:
什么构成了对对象的访问
具有 volatile 限定的类型是实现定义的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)