简化问题:
与内存屏障相比,由互锁操作导致的内存缓存一致性(或“刷新”)的时间安排是否有所不同?让我们考虑一下在C#中-任何互锁的操作与Thread.MemoryBarrier()的比较。我相信有区别。
背景:
我读到的有关内存障碍的信息很少-所有这些都对防止特定类型的内存交互指令重新排序产生了影响,但是我找不到有关它们是否应立即导致读/写队列刷新的一致信息。
实际上,我发现很少有人提到不能立即保证操作(只能保证防止特定的重新排序)。
例如。
Wikipedia:
“但是,要明确地说,这并不意味着在屏障完成时将完成任何操作;仅保证对操作完成的顺序(当它们完成时)”
Freebsd.org(屏障是特定于硬件的,因此我想特定的操作系统无关紧要):“内存屏障仅确定内存操作的相对顺序;它们不保证内存操作的时间安排”
另一方面,互锁操作(根据其定义)会导致立即刷新所有内存缓冲区,以确保更新了变量的最新值,从而导致内存子系统使用该值锁定整个高速缓存行,以防止任何对象访问(包括读取)其他CPU/核心,直到操作完成。
我是正确的还是我误会了?
免责声明:
这是我原来的问题的演变Variable freshness guarantee in .NET (volatile vs. volatile read)
编辑1:
修正了我关于互锁操作的声明-内联文本。
编辑2:
完全删除演示代码及其讨论(因为有些人提示信息过多)
最佳答案
要了解C#互锁操作,您需要了解Win32互锁操作。
“纯”互锁操作本身仅影响该操作直接引用的数据的新鲜度。
但是在Win32中,互锁操作曾经暗示了完整的内存屏障。我相信这主要是为了避免在较新的硬件上破坏旧程序。因此,InterlockedAdd做两件事:互锁添加(非常便宜,不影响缓存)和完整的内存屏障(相当繁琐的操作)。
后来,Microsoft意识到这很昂贵,并且增加了每个操作的版本,这些版本不执行或不执行部分内存屏障。
因此(在Win32世界中)现在几乎所有内容都有四个版本: InterlockedAdd(完整围栏),InterlockedAddAcquire(读取围栏),InterlockedAddRelease(写入围栏),纯InterlockedAddNoFence(无围栏)。
在C#世界中,只有一个版本,它与“经典” InterlockedAdd相匹配-它也可以完成全部内存操作。