lock指令(x64)

-- TOC --

多核CPU在处理共享内存的时候,需要保证原子性操作,通过lock指令实现。

__asm__ __volatile__(
        "   lock       ;\n"
        "   addl %1,%0 ;\n"
        : "=m"  (my_var)         // assume my_var is in shared memory
        : "ir"  (my_int), "m" (my_var)
        :                        /* no clobber-list */
        );

CPU的指令,在操作内存的时候,存在读--修改--写。这样的操作,在多CPU或多核场景下,原子性得不到保证,需要lock。

lock指令在其起作用的指令(accompanying instruction)执行期间,锁住共享内存,实现原子操作。总线锁或缓存锁!

能否使用lock prefix的指令:ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD and XCHG。而且,这些指令的目的操作数,必须在内存。

XCHG指令自带lock属性。

LOCK#信号就是我们经常说到的总线锁,处理器使用LOCK#信号达到锁定总线,来解决原子性问题,当一个处理器往总线上输出LOCK#信号时,其它处理器的请求将被阻塞,此时该处理器此时独占共享内存。总线锁这种做法锁定的范围太大了,导致CPU利用率急剧下降,因为使用LOCK#是把CPU和内存之间的通信锁住了,这使得锁定时期间,其它处理器不能操作其内存地址的数据 ,所以总线锁的开销比较大。

如果访问的内存区域已经缓存在处理器的缓存行中,P6系统和之后系列的处理器则不会声明LOCK#信号,它会对CPU的缓存中的缓存行进行锁定,在锁定期间,其它CPU不能同时缓存此数据,在修改之后,通过缓存一致性协议来保证修改的原子性,这个操作被称为“缓存锁”。

当操作的数据不能被缓存在处理器内部,或操作的数据跨多个缓存行时,也会使用总线锁。因为从P6系列处理器开始才有缓存锁,所以对于早些处理器是不支持缓存锁定的,只能总线锁。

有些指令自带lock,比如XCHG。

本文链接:https://cs.pynote.net/hd/asm/202303031/

-- EOF --

-- MORE --