linux smp原子操作

原子操作:就是在执行某一操作时不被打断。

linux原子操作问题来源于中断、进程的抢占以及多核smp系统中程序的并发执行。

对于临界区的操作可以加锁来保证原子性,对于全局变量或静态变量操作则需要依赖于硬件平台的原子变量操作。

因此原子操作有两类:一类是各种临界区的锁,一类是操作原子变量的函数。

对于arm来说,单条汇编指令都是原子的,多核smp也是,因为有总线仲裁所以cpu可以单独占用总线直到指令结束,多核系统中的原子操作通常使用内存栅障(memory barrier)来实现,即一个CPU核在执行原子操作时,其他CPU核必须停止对内存操作或者不对指定的内存进行操作,这样才能避免数据竞争问题。但是对于load update store这个过程可能被中断、抢占,所以arm指令集有增加了ldrex/strex这样的实现load update store的原子指令。

LDREX和STREX

ARM V7之后的LDREX、STREX指令可以解决这个问题。它保证2个读-修改-写序列有交叉的时候,只有1个可以写成功,另外一个则再次尝试。

为在多CPU环境中利用test_and_set指令实现进程互斥,硬件需要提供进一步的支持,以保证test_and_set指令执行的原子性. 这种支持目前多以“锁总线”(bus locking)的形式提供的

cmpxchg(void* ptr, int old, int new),如果ptr和old的值一样,则把new写到ptr内存,否则返回ptr的值,整个操作是原子的

明白了这些,再来看cmpxchgl,在Intel开发文档上说:
0F B1/r CMPXCHG r/m32, r32 MR Valid Valid* Compare EAX with r/m32. If equal, ZF is set and r32 is loaded into r/m32.Else, clear ZF and load r/m32 into EAX.

翻译一下:
比较eax和目的操作数(第一个操作数)的值,如果相同,ZF标志被设置,同时源操作数(第二个操作)的值被写到目的操作数,否则,清ZF标志,并且把目的操作数的值写回eax。

好了,把上面这句话套在cmpxchg上就是:
比较_old和(__ptr)的值,如果相同,ZF标志被设置,同时_new的值被写到(__ptr),否则,清ZF标志,并且把(*__ptr)的值写回_old。很明显,符合我们对cmpxchg的理解。

猜你喜欢

转载自blog.csdn.net/wdjjwb/article/details/88539462
今日推荐