C# 共享内存 - CPU 缓存的风险(非 volatile 读取)?

标签 c# shared-memory compiler-optimization cpu-architecture memory-barriers

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

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

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

但是 ..(如何)保证 CPU 不会缓存这个值? 与此一样,您可以用“volatile”标记变量以确保此行为,但在上述情况下如何管理,其中数据是通过指针通过不安全代码从内存中读取的。这会始终被视为 volatile 读取,还是不是 volatile 读取?

在后者的情况下,这是否意味着共享内存数据可能在 Microsoft 的实现中不同步 - 例如外部进程非常频繁地覆盖某个内存位置,而 C# 代码非常频繁地读取它,是否有将值缓存在 CPU 中而不是每次都从内存中重新读取的风险?

谢谢

最佳答案

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

也就是说,如果在指令序列中足够接近并且访问相同内存位置的两个加载可能会合并(假设 CPU 支持这种技术),如果它们之间没有加载序列化指令(加载屏障)。 我不认为ReadInt32 这样的大函数会发生这种情况(还考虑到函数 ReadInt32 调用的所有代码) .即使连续调用 ReadInt32 而调用之间没有任何代码,两次连续的 *((Int32*)(pointer)) 访问之间也会有数百条指令,各种类型由于依赖关系,在所有 x86 和 ARM 处理器上,将两次读取结合起来的机会几乎为零。处理器会在看到第二个之前很久就退出第一个读取。请注意,两个连续的读取可以合并为一个内存请求。

关于C# 共享内存 - CPU 缓存的风险(非 volatile 读取)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49776844/

相关文章:

c# - .NET 代码访问安全性中的 "ApplicaionDirectory"成员条件意味着什么?

c# - C# .net 中的这个声明是什么意思?

c# - 如何使用 Windows 添加到我的 c# Selenium Webdriver 套件以合并 native iPhone 应用程序测试

file - 跨进程共享文件描述符

c++ - 在静态库中运行代码,在 main() 之前,当链接器看不到对它的其他引用时

Clang 优化级别

c# - 将通用列表形式 DerivedClass 转换为 BaseClass

MPI 3 共享内存和缓存冲突

c# - 完全托管的共享内存 .NET 实现?

clang - -march = native使用Clang激活哪些标志?