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

C# lock语句如何确保处理器内同步?,c#,.net,multithreading,synchronization,C#,.net,Multithreading,Synchronization,我有一个同时执行两个线程的小测试应用程序。一个增加一个静态长\u值,另一个减少它。我已经通过ProcessThread.ProcessorAffinity确保线程与不同的物理(非HT)内核相关联,以强制处理器内通信,并且我已经确保它们在执行时间上重叠相当长的时间 当然,以下情况不会导致零: for (long i = 0; i < 10000000; i++) { _value += offset; } for(长i=0;i

我有一个同时执行两个线程的小测试应用程序。一个增加一个
静态长\u值
,另一个减少它。我已经通过
ProcessThread.ProcessorAffinity
确保线程与不同的物理(非HT)内核相关联,以强制处理器内通信,并且我已经确保它们在执行时间上重叠相当长的时间

当然,以下情况不会导致零:

for (long i = 0; i < 10000000; i++)
{
    _value += offset;
}
for(长i=0;i<10000000;i++)
{
_值+=偏移量;
}
因此,合乎逻辑的结论是:

for (long i = 0; i < 10000000; i++)
{
    Interlocked.Add(ref _value, offset);
}
for(长i=0;i<10000000;i++)
{
联锁。添加(参考值,偏移量);
}
这当然会导致零

但是,以下情况也会导致零:

for (long i = 0; i < 10000000; i++)
{
    lock (_syncRoot)
    {
        _value += offset;
    }
}
for(长i=0;i<10000000;i++)
{
锁定(\u syncRoot)
{
_值+=偏移量;
}
}
当然,
lock
语句确保读取和写入不会重新排序,因为它使用了完全隔离。但是,我找不到任何有关处理器缓存同步的信息。如果没有任何缓存同步,我想在两个线程都完成后,应该会看到与0的偏差


有人能向我解释一下
锁定
/
监视器。进入/退出
如何确保处理器缓存(一级/二级缓存)同步?在这种情况下,缓存一致性不取决于
锁定
。如果您使用
lock
语句,它将确保您的汇编程序命令不会混合。
a+=b
不是处理器的原子,它看起来像:

  • 将数据从内存加载到寄存器
  • 增量数据
  • 回存数据
如果没有锁,它可能是:

  • 将数据从内存加载到寄存器X
  • 将数据从内存加载到寄存器Y中
  • 增量数据(以X为单位)
  • 减量数据(Y)
  • 将数据存储回(从X)
  • 将数据存储回(从Y)//在这种情况下,增量丢失
但这不是缓存一致性,而是更高层次的特性

因此,
lock
不能确保缓存同步。缓存同步是一种处理器内部功能,它不依赖于代码。你可以读到它


当一个内核将一个值写入内存,然后当第二个内核尝试读取该值时,它的缓存中不会有实际副本,除非其缓存项无效,从而发生缓存未命中。此缓存未命中强制将缓存项更新为实际值

CLR内存模型。这取决于CLR实现者在真正的硬件上实施。但是,这是基于硬件的广告/理解行为,即。

对于一对
系统.Threading.Monitor.Enter()
系统.Threading.Monitor.Exit()
调用来说,
关键字只是语法上的糖分。
Monitor.Enter()
Monitor.Exit()
的实现建立了一个内存围栏,需要执行与体系结构相关的缓存刷新。因此,您的另一个线程将无法继续,直到它能够看到执行锁定部分所产生的存储。

“我已确保它们同时启动”。不完全是这样,您无法控制操作系统相对于其他应用程序如何调度应用程序的线程。但在大多数情况下,这不重要。对不起,表述错误。我已经确保它们在大致相同的时间开始,并且我已经确保它们在执行时间上重叠。更新了问题。感谢您的观察。请注意,并非所有处理器(如Blackfin)都会在硬件中自动缓存一致性。但可能所有有.net实现的处理器都有。你是说缓存一致性本身在软件中从来没有遇到过吗?你可以从代码中使用缓存进行操作(例如预取或清除命令),但据我所知,你不能从你的代码中操纵与缓存一致性相关的东西。谢谢你的回答。除此之外,Intel/AMD正在玩弄取消缓存一致性,因为它太过健谈,并且对于许多核心CPU来说都是一个大问题。每次CPU更改地址时,它必须广播到所有其他内核,以将任何相关缓存线标记为脏缓存线。另外,从我所读到的内容来看,“原子”更改在ARM多核系统上是昂贵的,因为没有硬件缓存一致性。因此,对于Win8 ARM多核系统来说,锁定/联锁是昂贵的调用。我不记得在哪里读过这篇文章,但我觉得很有趣。这也使得ARM更晶体管、更节能、更少的工作。但是,是什么过程使存储对另一个线程可见呢?