在本文中:http://www.drdobbs.com/parallel/volatile-vs-volatile/212701484?pgno=2
说,我们不能对 volatile
做任何优化,即使是 (where: 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 行之间 v
值可能会被 硬件设备更改(不是 CPU 无法工作的缓存一致性:网络适配器,GPU , FPGA, etc...) (sequentila/concurrency), 映射到这个内存位置。但只有当 v
不能缓存在 CPU 缓存 L1/2/3 中时才有意义,因为对于通常的(非 volatile
)变量,介于 1st 和 2nd 之间行太小的时候很可能触发缓存。
volatile
限定符是否保证不对该内存位置进行缓存?
回答:
- 不,
volatile
不保证不缓存此内存位置,并且在 C/C++ 标准或 compiler manual 中没有任何相关内容. - 使用内存映射区域, when memory mapped from device memory to CPU-memory is already marked as WC (写入组合)而不是 WB,取消缓存。 并且不需要进行缓存刷新。
- 相反,如果 CPU 内存映射到设备内存,那么顺便说一句,位于 CPU 晶体上的 Controller PCIE 正在监听从该设备通过 DMA 的数据,并更新(无效)CPU 缓存 L3 .在这种情况下,如果设备上的可执行代码使用
volatile
尝试执行相同的两行,它也会取消设备的缓存内存(例如在缓存中GPU-L2)。和 need not to do GPU-cache-flushing and need not to do CPU-cache-flushing 强>。同样对于 CPU 可能需要使用std::atomic_thread_fence(std::memory_order_seq_cst);
if L3-cache(LLC) coherency with DMA over PCIE, but L1/L2 is not .对于 nVidia CUDA,我们可以使用:void __threadfence_system();
- 发送未对齐的数据时,我们需要刷新 DMA Controller 缓存:(WDK:
KeFlushIoBuffers(), FlushAdapterBuffers()
) - 此外,我们可以通过 MTRR 寄存器将任何内存区域标记为未缓存的 WC 标记。
最佳答案
volatile
确保变量不会被“缓存”在 CPU 寄存器中。 CPU 缓存对程序员是透明的,如果另一个 CPU 写入另一个 CPU 缓存映射的内存,第二个 CPU 的缓存将失效,因此它将在下一次访问时再次从内存中重新加载值。
关于 Cache coherence 的事情
至于外部内存写入(通过 DMA 或其他独立于 CPU 的 channel ),您可能需要手动刷新缓存(参见 this SO 问题)
C 标准 §6.7.3 7:
What constitutes an access to an object that has volatile-qualified type is implementation-defined.
关于c++ - volatile 限定符是否取消了此内存的缓存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18550784/