.Net中是否有等效的XADD命令?毕竟,这是锁定/检查关键部分锁定或确保多线程环境中准确增量的最有效方法。
我查看了IL操作码,但找不到相应的操作符。
答案 0 :(得分:7)
获取锁定比使用简单的CPU指令要多得多。试图获得它而不是获得它的成本非常高。记录在2000到10,000台机器指令之间。线程上下文切换到另一个进程中的线程的数字越大,这需要重新加载虚拟内存页面转换表。
一种在多核CPU上有意义的非常常见的策略是自旋等待。代码进入紧密循环,大量燃烧CPU周期,试图获取锁定。它在这个循环中花费的确切时间在技术上是一个可调项,但在实践中没有太大的区别。
Anyhoo,它是CLR的工作,编译器是隐藏实现细节。执行此操作的一个核心类是Monitor类。它在C#中使用lock语句时使用,例如,编译器自动将其转换为Monitor.Enter调用,自动生成try和finally块,finally块执行Leave()方法。
这些方法的实现在CLR中。那里有相当多的代码,另一件事就是处理“公平”。这可以确保线程不会饿死,试图获得锁定。该代码是用C ++编写的,与原始CPU指令相差甚远。它最终归结为实现实际锁定的实际代码。是的,这是用汇编编写的,至少在CLR的共享源版本中。该代码存在于PAL(平台适配器层)中,其x86版本如下所示:
FASTCALL_FUNC CompareExchangeMP,12
_ASSERT_ALIGNED_4_X86 ecx
mov eax, [esp+4] ; Comparand
lock cmpxchg [ecx], edx
retn 4 ; result in EAX
FASTCALL_ENDFUNC CompareExchangeMP
带锁定前缀的cmpxchng CPU指令是实现锁定的典型指令。您的xadd也被覆盖,用于Interlocked.Add:
FASTCALL_FUNC ExchangeAddUP,8
_ASSERT_ALIGNED_4_X86 ecx
xadd [ecx], edx ; Add Value to Target
mov eax, edx
retn
FASTCALL_ENDFUNC ExchangeAddUP
但这通常不用于锁。如果您想亲眼看到这个,请下载SSCLI20源代码并查看clr \ src \ wm \ i386 \ asmhelpers.asm。是否实际在CLR的当前发布版本中使用是一个悬而未决的问题。这是非常核心的,有点可能。 Monitor方法实现在clr \ vm \ syncblk.cpp,AwareLock类中。我很确定它的SSCLI20版本不是你机器上运行的版本,他们一直在修改“公平”算法。
答案 1 :(得分:3)
.NET中最接近的等价物是使用Interlocked class。例如,您可以使用Interlocked.Add在多线程环境中获得安全,准确的增量。
答案 2 :(得分:1)
查看Interlocked课程,特别注意Interlocked.Add
。以下是其在IL中的使用示例。
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int32 a,
[1] int32 b)
L_0000: ldc.i4.5
L_0001: stloc.0
L_0002: ldc.i4.7
L_0003: stloc.1
L_0004: ldloca.s a
L_0006: ldloc.1
L_0007: call int32 [mscorlib]System.Threading.Interlocked::Add(int32&, int32)
L_000c: pop
L_000d: ret
}