【问题标题】:.Net equivalent of the x86 ASM command XADD.Net 等效于 x86 ASM 命令 XADD
【发布时间】:2010-07-26 20:19:32
【问题描述】:

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

我查看了 IL 操作码,但找不到等效的操作码。

【问题讨论】:

    标签: .net multithreading synchronization cil


    【解决方案1】:

    获取锁不仅仅是一条简单的 CPU 指令。试图获得它而不获得它的成本非常高。记录在 2000 到 10,000 条机器指令之间。较大的线程上下文切换到另一个进程中的线程,这需要重新加载虚拟内存页面转换表。

    在多核 CPU 上有意义的一个非常常见的策略是自旋等待。代码进入一个紧密循环,大量消耗 CPU 周期,试图获取锁。它在此循环中花费的确切时间在技术上是一个可调项目,但在实践中并没有太大区别。

    无论如何,这是 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
    

    带有lock前缀的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 版本不是你机器上运行的,他们一直在修补“公平”算法。

    【讨论】:

    • 感谢您的详细回答,汉斯 :)
    【解决方案2】:

    .NET 中最接近的等效项是使用Interlocked class。例如,您可以使用Interlocked.Add 在多线程环境中获得安全、准确的增量。

    【讨论】:

      【解决方案3】:

      查看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 
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-22
        • 1970-01-01
        • 1970-01-01
        • 2011-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多