lock语句如何确保内部处理器同步?

Pie*_*kel 10 .net c# multithreading synchronization

我有一个小的测试应用程序,它同时执行两个线程.一个递增a static long _value,另一个递减a.我已经确保ProcessThread.ProcessorAffinity线程与不同的物理(无HT)内核相关联以强制进行内部处理器通信,并确保它们在执行时间内重叠了很长时间.

当然,以下不会导致零:

for (long i = 0; i < 10000000; i++)
{
    _value += offset;
}
Run Code Online (Sandbox Code Playgroud)

因此,合乎逻辑的结论是:

for (long i = 0; i < 10000000; i++)
{
    Interlocked.Add(ref _value, offset);
}
Run Code Online (Sandbox Code Playgroud)

这当然导致零.

但是,以下内容也会导致零:

for (long i = 0; i < 10000000; i++)
{
    lock (_syncRoot)
    {
        _value += offset;
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,该lock语句确保读取和写入不会重新排序,因为它使用了完整的栅栏.但是,我找不到任何有关处理器缓存同步的信息.如果没有任何缓存同步,我认为在两个线程完成后我应该看到偏离0?

有人可以向我解释如何lock/ Monitor.Enter/Exit确保处理器缓存(L1/L2缓存)是同步的吗?

oxi*_*min 9

在这种情况下,缓存一致性不依赖于lock.如果使用lock语句,则可确保汇编器命令不会混合. a += b它不是处理器的原子,它看起来像:

  • 将数据从内存加载到寄存器中
  • 增加数据
  • 存储数据

没有锁定它可能是:

  • 将数据从内存加载到寄存器X中
  • 将数据从内存加载到寄存器Y中
  • 增量数据(在X中)
  • 递减数据(在Y中)
  • 存储数据(来自X)
  • 存储数据(从Y开始)//在这种情况下,增量会丢失.

但它不是关于缓存一致性,而是一个更高级别的功能.

因此,lock不能确保缓存是同步的.缓存同步是处理器内部功能,不依赖于代码.你可以在这里阅读它.

当一个内核将值写入内存,然后当第二个内核尝试读取该值时,它将不会在其高速缓存中具有实际副本,除非其高速缓存条目无效,因此发生高速缓存未命中.并且此缓存未命中强制缓存条目将更新为实际值.