volatile限定符是否取消了对此内存的缓存?

时间:2013-08-31 17:16:59

标签: c++ c caching c++11 concurrency

在本文中: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<>

无法完成,因为第1行和第2行之间的值可以由硬件设备更改(不是CPU无法正常工作的缓存一致性:网络适配器,GPU,FPGA,等...)(顺序/并发),映射到此内存位置。但只有v无法缓存在CPU缓存L1 / 2/3中才有意义,因为对于通常(非v)变量,在第1行和第2行之间的时间太短,并且可能会触发缓存。

volatile限定符是否保证不对此内存位置进行缓存?

答案:

  1. 不,volatile 不保证此内存位置没有缓存,并且在C / C ++标准或compiler manual中没有任何相关内容。
  2. 使用内存映射区域 when memory mapped from device memory to CPU-memory is already marked as WC (写入合并)而不是WB,取消缓存。 并且不需要执行缓存刷新
  3. 相反,如果CPU内存映射到设备内存,那么偶然地,位于CPU晶体上的控制器PCIE正在侦听从该设备通过DMA的数据,并更新(无效)CPU缓存L3 。在这种情况下,如果使用 volatile的设备上的可执行代码尝试执行相同的两行,它也会取消设备的缓存(例如,在缓存GPU-L2中) )。 need not to do GPU-cache-flushing and need not to do CPU-cache-flushing 。此外,对于CPU,可能需要使用volatile if L3-cache(LLC) coherency with DMA over PCIE, but L1/L2 is not。对于nVidia CUDA,我们可以使用:void __threadfence_system();
  4. 我们需要刷新DMA-controllers-cache ,在发送未对齐的数据时:(WDK: KeFlushIoBuffers(), FlushAdapterBuffers())
  5. 此外,我们可以通过MTRR寄存器将任何内存区域标记为未标记为WC标记。

2 个答案:

答案 0 :(得分:6)

volatile确保变量不会在CPU寄存器中“缓存”。 CPU缓存对程序员是透明的,如果另一个CPU写入由另一个CPU的缓存映射的内存,则第二个CPU的缓存会失效,因此它将在下次访问时再次从内存重新加载该值。

关于Cache coherence

的内容

对于外部存储器写入(通过DMA或其他独立于CPU的通道),您可能需要手动刷新缓存(请参阅this SO问题)


C标准§6.7.37:

  

什么构成对对象的访问权限   volatile的限定类型是实现定义的。

答案 1 :(得分:0)

volatile的语义是实现定义的。如果编译器知道在执行某些代码时将禁用中断,并且知道在目标平台上除了中断处理程序之外就没有其他方法可以观察到某些存储上的操作,则它可以将volatile寄存器缓存-此类存储中的限定变量与可以缓存普通变量的存储条件一样,只要它记录了这种行为即可。

请注意,行为的哪些方面被认为是“可观察的”可以通过实现以某种方式定义。如果某个实现记录了它不打算在使用主RAM访问来触发所需的外部可见操作的硬件上使用,则在该实现上对主RAM的访问将是“不可观察的”。如果不关心是否实际看到任何此类访问,则该实现将与能够物理观察此类访问的硬件兼容。但是,如果需要这样的访问,就像访问被视为“可观察的”那样,则编译器将不会要求兼容性,因此不会对任何事情做任何保证。