.Net相当于x86 ASM命令XADD

时间:2010-07-26 20:19:33

标签: .net multithreading synchronization cil

.Net中是否有等效的XADD命令?毕竟,这是锁定/检查关键部分锁定或确保多线程环境中准确增量的最有效方法。

我查看了IL操作码,但找不到相应的操作符。

3 个答案:

答案 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 
}