昨天我发布了this question关于如何编写快速螺旋锁。感谢Cory Nelson,我似乎找到了一种超越我的问题中讨论的其他方法的方法。我使用CMPXCHG
指令来检查锁是否为0,从而释放。 CMPXCHG
运行于'BYTE',WORD
和DWORD
。我会假设该指令在上运行得更快。但我写了一个锁实现每个数据类型:cmpxchg for WORD比BYTE更快
inline void spin_lock_8(char* lck)
{
__asm
{
mov ebx, lck ;move lck pointer into ebx
xor cl, cl ;set CL to 0
inc cl ;increment CL to 1
pause ;
spin_loop:
xor al, al ;set AL to 0
lock cmpxchg byte ptr [ebx], cl ;compare AL to CL. If equal ZF is set and CL is loaded into address pointed to by ebx
jnz spin_loop ;jump to spin_loop if ZF
}
}
inline void spin_lock_16(short* lck)
{
__asm
{
mov ebx, lck
xor cx, cx
inc cx
pause
spin_loop:
xor ax, ax
lock cmpxchg word ptr [ebx], cx
jnz spin_loop
}
}
inline void spin_lock_32(int* lck)
{
__asm
{
mov ebx, lck
xor ecx, ecx
inc ecx
pause
spin_loop:
xor eax, eax
lock cmpxchg dword ptr [ebx], ecx
jnz spin_loop
}
}
inline spin_unlock(<anyType>* lck)
{
__asm
{
mov ebx, lck
mov <byte/word/dword> ptr [ebx], 0
}
}
锁,然后用下面的伪代码进行测试(请注意,LCM-指针总是将4指向的地址整除):
<int/short/char>* lck;
threadFunc()
{
loop 10,000,000 times
{
spin_lock_8/16/32 (lck);
spin_unlock(lck);
}
}
main()
{
lck = (char/short/int*)_aligned_malloc(4, 4);//Ensures memory alignment
start 1 thread running threadFunc and measure time;
start 2 threads running threadFunc and measure time;
start 4 threads running threadFunc and measure time;
_aligned_free(lck);
}
我已经得到了以2个物理核心能够运行4个线程(Ivy Bridge)的处理器在msecs上测得的以下结果。
1 thread 2 threads 4 threads
8-bit 200 700 3200
16-bit 200 500 1400
32-bit 200 900 3400
数据表明所有函数都需要等量的时间才能执行。但是当多线程必须检查使用16位的lck == 0
可以显着更快。这是为什么?我不认为这与lck
的对齐有关系吗?
在此先感谢。
'我知道这不是很多的区别,但作为螺旋锁是一个沉重使用的对象' - 天堂在30多年的多线程软件开发中没有明确地使用过单一的。 – 2012-08-15 23:23:05
尝试移动“暂停”指令进入旋转循环而不是循环之外。 16位指令需要额外的0x66/0x67前缀字节,使它们比8位或32位指令略大/慢。所以额外开销可能会减慢循环,以减少16位情况下的争用。 – 2012-08-16 00:41:13
如果这些锁导致随机损坏,我不会惊讶,因为它们修改ebx(一个被调用者保存寄存器)而不保存和恢复它,这可能会破坏调用者期望保留的一些值。改用edx。 – 2012-08-16 00:46:02