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

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

当然,以下不会导致零:

 for (long i = 0; i < 10000000; i++) { _value += offset; } 

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

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

这当然导致零。

但是,以下也导致零:

 for (long i = 0; i < 10000000; i++) { lock (_syncRoot) { _value += offset; } } 

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

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

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

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

没有锁定它可能是:

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

但它不是关于缓存一致性,而是一个更高级别的function。

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

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

CLR内存模型保证(要求)加载/存储不能越过围栏 。 CLR实施者可以在真实硬件上强制执行此操作 。 但是,这是基于硬件的广告/理解行为,这可能是错误的 。

lock关键字只是一对System.Threading.Monitor.Enter()System.Threading.Monitor.Exit()调用的语法糖。 Monitor.Enter()Monitor.Exit()建立了一个内存栏,需要执行适当的体系结构缓存刷新。 所以你的其他线程将不会继续,直到它可以看到执行锁定部分产生的商店。