-- 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 --