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()
建立了一个内存栏,需要执行适当的体系结构缓存刷新。 所以你的其他线程将不会继续,直到它可以看到执行锁定部分产生的商店。