3

我了解 和 的Interlocked.Increment功能lock()。但我对何时使用其中一种感到困惑。据我所知,Interlocked.Increment增量共享 int/long 值,而 aslock()旨在锁定代码区域。

例如,如果我想更新字符串值,可以使用lock()

lock(_object)
{
    sharedString = "Hi";
}

但是,这在课堂上是不可能的Interlocked

  • 为什么这不能通过 来完成Interlocked
  • 这些同步机制有什么区别?
4

3 回答 3

7

Interlocked.Increment相关方法依靠硬件指令对单个32bit或64bit内存值进行同步修改,保证访问同一个值的多个线程不会读/写陈旧数据。这是必要的,因为在硬件级别,处理器具有内存值的本地/总线副本(出于性能考虑,通常称为总线内存或 cpu 缓存)。

lock(){}对一段代码执行同步,而不是单个整数值。而不是依靠硬件指令来同步对变量的访问,结果代码而是依靠操作系统同步原语(软件,而不是硬件)来保护内存和代码执行。

此外,lock() 的使用会发出内存屏障,确保从多个 CPU 访问相同的变量会产生同步(非陈旧)数据。这在其他语言/平台中并非如此,在这些语言/平台中,必须显式执行内存屏障和防护。

对整数值使用方法更有效,Interlocked因为硬件具有执行必要同步的本机支持。但是这种硬件支持只存在于 __int32 和 __int64 等本机积分,因为硬件没有更高级别的复杂类型的概念,因此不会从Interlocked类型中公开这种高级方法。因此,您不能使用Interlocked同步分配System.String或任何System.Object派生类型。

(即使如果您使用较低级别的语言,可以使用相同的硬件指令来分配指向字符串值的指针,但事实是,在 .NET 中,字符串对象不表示为指针,因此它不是可以在任何“纯”.NET 语言中使用。我正在避免这样一个事实,即您可以使用不安全的方法来解析指针并在您真的想要的情况下对字符串值进行联锁分配,但我觉得这不是真的你在问什么,而且 Interlocked 不支持这一点,因为需要在引擎盖下进行 GC 固定,这可能会比使用更昂贵和更具侵入性lock()。)

因此,对于“引用类型”的同步修改/分配,您将需要使用同步原语(即 lock(){}、Monitor 等)。如果您只需要同步一个整数值(Int32、Int64),那么使用 Interlocked 方法会更有效。如果有多个整数值要同步,则使用 lock() 语句可能仍然有意义,例如增加一个整数同时减少第二个整数,其中两者都需要作为单个逻辑操作进行同步。

于 2013-12-14T22:10:39.113 回答
6

Interlocked.Increment可以而且应该用于增加共享int变量。功能使用Interlocked.Increment与以下相同:

lock(_object)
{
   counter++;
}

Interlocked.Increment在性能方面要便宜得多。

于 2012-09-07T09:13:32.163 回答
0

如果要交换引用值,并在原子操作中返回原始值,可以使用Interlocked.Exchange. Interlocked.Increment完全按照它所说的那样做:它增加一个数字。

但是,简单地将引用值分配给变量,或者任何 32 位值类型在 .NET 中都是原子的。我能想到的唯一另一种情况(后者不成立)是,如果您创建一个打包结构并设置属性,这将强制编译器不在 4 字节边界对齐成员(但这不是您要做的事情真的经常)。

于 2012-09-07T09:16:19.290 回答