代码之家  ›  专栏  ›  技术社区  ›  Bogey

C#共享内存-CPU缓存风险(非易失性读取)?

  •  2
  • Bogey  · 技术社区  · 6 年前

    我想知道C#中共享内存的实现。MemoryMappedViewAccessor允许您从共享内存区域读取数据。

    现在,memoryMappedViewAccessor继承自UnmanagedMemoryAccessor,它排除了ReadInt32()等方法,其实现可以在这里看到 https://referencesource.microsoft.com/#mscorlib/system/io/unmanagedmemoryaccessor.cs,7632fe79d4a8ae4c . 原则上,它似乎使用相对简单的不安全指针运算/转换,

     pointer += (_offset + position);
     result = *((Int32*)(pointer));
    

    但是(如何)保证CPU不会缓存此值? 如中所示,您可以用“volatile”标记变量以确保这种行为,但在如上所述的情况下,如何管理这种行为,即指针通过不安全的代码从内存中读取数据。这总是被视为易失性读取,还是不易失性读取?

    对于后者,这难道不意味着共享内存数据在Microsoft的实现中可能会不同步吗?例如,外部进程非常频繁地重写某个内存位置,而C#代码非常频繁地读取该位置,每次都有可能将值缓存在CPU中,而不是从内存中新读取?

    谢谢

    1 回复  |  直到 6 年前
        1
  •  3
  •   Hadi Brais    6 年前

    这部分代码 *((Int32*)(pointer)) 编译为访问内存位置的机器指令。所以每次 ReadInt32 调用时,将访问指定的内存位置。If by“是否保证CPU不会缓存此值?”您指的是CPU缓存,那么硬件中实现的缓存一致性将确保访问最新值。否则,如果您引用的是用于在发出加载的指令失效之前保存加载数据的内部缓冲结构,那么一旦加载失效,对同一内存位置的任何其他后续加载都必须向缓存层次结构发送另一个内存请求(内部缓冲区不再包含数据)。

    我不认为 ReadInt32 (同时考虑所有功能代码 电话)。即使打电话 ReadInt32 连续调用之间没有任何代码,两个连续调用之间将有数百条指令 *((Int32*)(指针)) 对于各种依赖性的访问,在所有x86和ARM处理器上结合这两种读取的机会几乎为零。处理器早在看到第二次读取之前就已经停止了第一次读取。请注意,两个连续的读取可以合并到一个内存请求中。