C volatile变量和Cache Memory

Mic*_*nel 33 c computer-science volatile computer-architecture memorycache

缓存由缓存硬件透明地控制到处理器,因此如果我们在C程序中使用volatile变量,我的程序如何保证每次从指定的实际内存地址而不是缓存中读取数据.

我的理解是,

  1. Volatile关键字告诉编译器不应优化变量引用,并应按代码中的编程读取.

  2. 缓存由缓存硬件透明地控制,因此当处理器发出地址时,它不知道数据是来自缓存还是来自内存.

因此,如果我需要每次都需要读取一个内存地址,我怎样才能确保它不是从缓存引用而是从所需的地址引用?

有些怎么样,这两个概念并不合适.请说明它是如何完成的.

(想象一下我们在缓存中有回写策略(如果需要分析问题))

谢谢你,Microkernel :)

And*_*ell 31

固件开发人员在这里.这是嵌入式编程中的一个标准问题,也是许多(即使非常有经验的)开发人员绊倒的问题.

我的假设是您正在尝试访问硬件寄存器,并且该寄存器值可能随时间而变化(无论是中断状态,定时器,GPIO指示等).

volatile关键字是唯一的解决方案的一部分,并且在许多情况下可能不是必需的.这会导致变量在每次使用时从内存中重新读取(与编译器优化或跨多个用途存储在处理器寄存器中相反),但是读取的"内存"是否是实际的硬件寄存器与缓存位置相比,您的代码不知道,并且不受volatile关键字的影响.如果您的函数只读取寄存器一次,那么您可以放弃volatile,但作为一般规则,我将建议大多数硬件寄存器应定义为volatile.

更大的问题是缓存和缓存一致性.这里最简单的方法是确保您的寄存器位于未缓存的地址空间中.这意味着每次访问寄存器时,都可以保证读/写实际的硬件寄存器而不是高速缓冲存储器.更复杂但可能性能更好的方法是使用缓存的地址空间,并让您的代码手动强制缓存更新,以适应这种特定情况.对于这两种方法,如何实现这一点取决于体系结构,超出了问题的范围.它可能涉及MTRR(用于x86),MMU,页表修改等.

希望有所帮助.如果我错过了什么,请告诉我,我会扩展我的答案.


Meh*_*dad 7

我的建议是将页面标记为虚拟内存管理器未缓存.
在Windows中,这是通过PAGE_NOCACHE调用时设置完成的VirtualProtect.

出于某种不同的目的,SSE 2指令具有_mm_stream_xyz防止高速缓存污染的指令,尽管我认为它们不适用于您的情况.

在任何一种情况下,都没有可行的方法在C中做你想做的事情; 你必须使用操作系统功能.

  • @Microkernel:好的!:)基本上,操作系统将所有内存管理信息存储在内存中的"页表"中,并告诉CPU在哪里查找信息.然后CPU管理所有内容,并在操作系统无法决定做什么时向操作系统询问"帮助".你可以阅读有关分页[here](http://wiki.osdev.org/Paging)和缓存[here](http://wiki.osdev.org/CPU_Caches); 如果您还有任何疑问,请与我联系.(这就是为什么他们说操作系统位于硬件和软件之间 - 它确实如此!) (4认同)
  • 那么,这取决于平台吗?那么,Cache不是由缓存硬件控制的吗?(如果硬件完全管理缓存,那么它不会检查标志 PAGE_NOCACHE 对吗?) (2认同)
  • @Microkernel:它**由硬件**管理。但是操作系统告诉硬件要做什么(毕竟,硬件不知道操作系统想要如何管理内存),而您则要求操作系统做您想做的事情。*所有这些信息都存储在——猜猜在哪里?——内存本身。*不过,这是一个被动的过程——操作系统仅在出现问题(例如页面错误)时进行干预。除此之外,硬件只是继续执行操作系统要求它执行的操作,而无需操作系统干预。 (2认同)

Cra*_*lus 7

从你的问题来看,你有一种误解.
Volatile关键字与您描述的缓存无关.

volatile为变量指定关键字时,它会提示编译器不要进行某些优化,因为此变量可能会意外地从程序的其他部分更改.

这里的意思是编译器不应该重用已经加载到寄存器中的值,而是再次访问存储器,因为寄存器中的值不能保证与存储在存储器中的值相同.

关于高速缓冲存储器的其余部分与程序员没有直接关系.

我的意思是CPU的任何高速缓冲存储器与RAM的同步是一个完全不同的主题.