【发布时间】:2010-07-26 20:19:32
【问题描述】:
.Net 中是否有等效的 XADD 命令?毕竟,这是为关键部分锁定/检查锁定或确保在多线程环境中准确增量的最有效方法。
我查看了 IL 操作码,但找不到等效的操作码。
【问题讨论】:
标签: .net multithreading synchronization cil
.Net 中是否有等效的 XADD 命令?毕竟,这是为关键部分锁定/检查锁定或确保在多线程环境中准确增量的最有效方法。
我查看了 IL 操作码,但找不到等效的操作码。
【问题讨论】:
标签: .net multithreading synchronization cil
获取锁不仅仅是一条简单的 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 版本不是你机器上运行的,他们一直在修补“公平”算法。
【讨论】:
.NET 中最接近的等效项是使用Interlocked class。例如,您可以使用Interlocked.Add 在多线程环境中获得安全、准确的增量。
【讨论】:
查看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
}
【讨论】: