.Net 相当于 x86 ASM 命令 XADD

发布于 2024-09-11 04:01:08 字数 98 浏览 5 评论 0原文

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

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

Is there an equivalent of the XADD command in .Net? This is, after all, the most efficient method of locking / checking locks for critical sections or for ensuring accurate increments in a multi-threaded environment.

I looked through the IL opcodes, but couldn't find an equivalent.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦巷 2024-09-18 04:01:08

获取锁不仅仅是简单的 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 版本不是你的机器上运行的,他们一直在修改“公平”算法。

There's a lot more to acquiring a lock than a simple CPU instruction. The cost of trying to acquire it and not getting it is very high. Documented to be somewhere between 2000 and 10,000 machine instructions. The higher number for thread context switches to a thread in another process, that requires reloading the virtual memory page translation tables.

A very common strategy that makes sense on multi-core CPUs is a spin-wait. The code goes into a tight loop, burning CPU cycles heavily, trying to acquire the lock. The exact amount of time it spends in this loop is technically a tunable item, but doesn't make much difference in practice.

Anyhoo, it is the job of the CLR and the compiler is to hide the implementation details. One core class that does this is the Monitor class. It is used when you use the lock statement in C# for example, the compiler automatically translates that to a Monitor.Enter call, auto-generating a try and finally block, the finally block executes the Leave() method.

The implementation of these methods is in the CLR. There's a fairly good chunk of code there, another thing it does is dealing with a "fairness". Which makes sure that threads cannot starve, trying to acquire the lock. That code is written in C++, still pretty far removed from raw CPU instructions. It ultimately boils down to the actual code that implements the actual lock. Yes, that's written in assembly, at least in the shared source version of the CLR. That code lives in the PAL (Platform Adapter Layer), the x86 version of it looks like this:

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

The cmpxchng CPU instruction with the lock prefix is the typical one to implement locks. Your xadd is covered too though, used for 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

But that isn't typically used for locks. If you want to see this for yourself, download the SSCLI20 source code and have a look-see at clr\src\wm\i386\asmhelpers.asm. Whether that is actually used in the currently shipping version of the CLR is an open question. It's pretty core, so somewhat likely. The Monitor method implementations are in clr\vm\syncblk.cpp, AwareLock class. I'm pretty sure that the SSCLI20 version of it is not what's running on your machine, they've been tinkering with the "fairness" algorithm.

似最初 2024-09-18 04:01:08

.NET 中最接近的等效项是使用 Interlocked 类< /a>.例如,您可以使用 Interlocked.Add 来安全、准确多线程环境中的增量。

The closest equivelent in .NET would be to use the Interlocked class. For example, you can use Interlocked.Add to have safe, accurate increments in a multi-threaded environment.

葬シ愛 2024-09-18 04:01:08

查看 Interlocked 类,特别注意 互锁。添加。以下是其在 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 
}

Take a look at the Interlocked class paying particular attention to Interlocked.Add. The following is an example of its usage in 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 
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文