Interlocked.Increment 实际上是做什么的?

22

Interlocked.Increment 似乎是在多线程代码中最常见/简单的操作之一。

我认为该方法的功能是某种模式,任何有线程经验的人都能够复制。

所以基本上我想知道的是,是否有人能够提供一个精确的副本(并解释它的工作原理)来模拟 Interlocked.Increment 方法实际上是在内部执行什么操作? (我已经寻找了实际方法的源代码,但未能找到)


我必须说,你的假设是一种模式,并且每个编写多线程代码的人都知道它,这种想法很好,但最终是不正确的。我不得不遗憾地补充一句:)。根据我的经验,许多人认为Interlocked方法奇怪,通常是不必要的,或者更糟糕的是,根本不考虑它们,因为他们不知道Interlocked方法。 - ipavlu
3个回答

14

根据Albahari先生的说法,它有两个作用:

  • 使操作的原子性为操作系统和虚拟机所知,从而使例如在32位系统上进行的64位值的操作成为原子操作
  • 生成full fence,限制对Interlocked变量的重新排序和缓存

请参考链接中的一些示例。


在x86/64上,在cas之后您不需要额外的fence。通常实现只是一个循环load/increment/cas(在成功的cas时中断)。 - bestsss

9

我认为这是一个实现细节,但可以通过检查JIT编译的代码来看待它。考虑以下示例。

private static int Value = 42;
public static void Foo() {
   Interlocked.Increment(ref Value);
}

在x86上,它生成以下内容。
lock inc dword <LOCATION>

lock修饰符锁定总线,以防止多个CPU更新相同的数据位置。

在x64上生成的代码为:

lock xadd dword ptr <LOCATION>,eax

你能告诉我为什么在x64上使用“lock xadd”而不是“lock add”的原因吗? - Nubok
2
“lock inc dword <location>” 语句如何处理返回值? - supercat

1

我会期望它是一个对InterlockedIncrement64 Win32 API调用的封装。


编辑:我看到这是一个非常简短的回答。稍微扩展一下:复制函数的功能很容易,但无法复制其性能。大多数CPU都有本地指令,可以为您提供原子“交换和添加”指令,因此您希望使用该指令来实现您的函数,并且我预计从C#内部实现该操作的最简单方法是进行win32 API调用。有关此主题的更多背景,请查看this whitepaper


1
Interlocked Win32 APIs已实现为编译器内置函数。 - David Heffernan
@David 对于64位的Windows系统是正确的,但它们也适用于32位的系统。无论如何,Brian的答案已经通过检查JIT输出提供了答案,这表明代码直接发出必要的x86指令。 - vhallac
1
即使是32位,它们也被实现为编译器内置函数。虽然可以从kernel32中获得导出,但所有最近的编译器都使用内置函数以获得明显的性能提升。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接