“最轻量级的锁”,通常也叫”原子操作”,之所以加引号是因为他们在汇编级别并不是原子操作,是用多条指令完成的,这些操作大多都是利用CPU支持的汇编指令.在某些构架过时的CPU体系结构上,它们应该是用比较重量级的线程内锁实现的吧(我的猜测).
最常见的原子操作有Compare and Exchange,Self Increase/Decrease等等
80486 CPU相关指令:
LOCK:这是一个指令前缀,在所对应的指令操作期间使此指令的目标操作数指定的存储区域锁定,以得到保护。
XADD:先交换两个操作数的值,再进行算术加法操作。多处理器安全,在80486及以上CPU中支持。
CMPXCHG:比较交换指令,第一操作数先和AL/AX/EAX比较,如果相等ZF置1,第二操作数赋给第一操作数,否则ZF清0,第一操作数赋给AL/AX/EAX。多处理器安全,在80486及以上CPU中支持。
XCHG:交换两个操作数,其中至少有一个是寄存器寻址.其他寄存器和标志位不受影响.
80486以上都支持这四个操作,因此当今几乎100%CPU都支持这两个指令,也能由此用标准C和C++写出一系列几乎可以跨平台的”原子操作”函数和Lock-Free数据结构和算法.
64位平台也有一系列的相关指令,当然他们也有以上提到的指令,其下的64位原子操作函数应该和32位的分开(要问为什么?我现在告诉你恐怕你印象不深,接着看这一系列吧),而道理完全一样.因此,不存在跨CPU体系结构的问题)
“原子操作”函数:
由以上提供的几个汇编指令,我们可以做出以下实现,这些都是最常用的原语.
比较后交换
long __stdcall CompareExchange(long volatile* Destination,long Exchange,long Comperand)
{
__asm
{
mov ecx, Destination;
mov edx, Exchange;
mov eax, Comperand;
lock cmpxchg [ecx], edx;
}
}
交换
long __stdcall Exchange(long volatile* Target,long Value)
{
__asm
{
mov ecx, Target;
mov edx, Value;
label:
lock cmpxchg [ecx], edx;//加
jnz short label;
}
}
自减
long __stdcall Decrement(long volatile* Addend)
{
__asm
{
mov ecx, Addend;
mov eax, 0FFFFFFFFh;//-1
lock xadd [ecx], eax; //加-1
dec eax;
}
}
自增
long __stdcall Increment(long volatile* Addend)
{
__asm
{
mov ecx, Addend;
mov eax, 1;
lock xadd [ecx], eax; //加
inc eax;
}
}
相加后交换
long __stdcall ExchangeAdd(long volatile* Addend,long Value)
{
__asm
{
mov ecx, Addend;
mov eax, Value;
lock xadd [ecx], eax;
}
}
最常见的原子操作有Compare and Exchange,Self Increase/Decrease等等
80486 CPU相关指令:
LOCK:这是一个指令前缀,在所对应的指令操作期间使此指令的目标操作数指定的存储区域锁定,以得到保护。
XADD:先交换两个操作数的值,再进行算术加法操作。多处理器安全,在80486及以上CPU中支持。
CMPXCHG:比较交换指令,第一操作数先和AL/AX/EAX比较,如果相等ZF置1,第二操作数赋给第一操作数,否则ZF清0,第一操作数赋给AL/AX/EAX。多处理器安全,在80486及以上CPU中支持。
XCHG:交换两个操作数,其中至少有一个是寄存器寻址.其他寄存器和标志位不受影响.
80486以上都支持这四个操作,因此当今几乎100%CPU都支持这两个指令,也能由此用标准C和C++写出一系列几乎可以跨平台的”原子操作”函数和Lock-Free数据结构和算法.
64位平台也有一系列的相关指令,当然他们也有以上提到的指令,其下的64位原子操作函数应该和32位的分开(要问为什么?我现在告诉你恐怕你印象不深,接着看这一系列吧),而道理完全一样.因此,不存在跨CPU体系结构的问题)
“原子操作”函数:
由以上提供的几个汇编指令,我们可以做出以下实现,这些都是最常用的原语.
比较后交换
long __stdcall CompareExchange(long volatile* Destination,long Exchange,long Comperand)
{
__asm
{
mov ecx, Destination;
mov edx, Exchange;
mov eax, Comperand;
lock cmpxchg [ecx], edx;
}
}
交换
long __stdcall Exchange(long volatile* Target,long Value)
{
__asm
{
mov ecx, Target;
mov edx, Value;
label:
lock cmpxchg [ecx], edx;//加
jnz short label;
}
}
自减
long __stdcall Decrement(long volatile* Addend)
{
__asm
{
mov ecx, Addend;
mov eax, 0FFFFFFFFh;//-1
lock xadd [ecx], eax; //加-1
dec eax;
}
}
自增
long __stdcall Increment(long volatile* Addend)
{
__asm
{
mov ecx, Addend;
mov eax, 1;
lock xadd [ecx], eax; //加
inc eax;
}
}
相加后交换
long __stdcall ExchangeAdd(long volatile* Addend,long Value)
{
__asm
{
mov ecx, Addend;
mov eax, Value;
lock xadd [ecx], eax;
}
}