Go语言atomic包CompareAndSwapInt32函数
请说明下面代码书写是否正确?
看到上面最重点的是要理解函数:atomic.CompareAndSwapInt32
点击这个函数找到:

之后找到这个函数实现:

之后找到这个汇编函数:

这边先将一些汇编基础指令意思贴出来:


寄存器fp(frame pointer) 用作帧指针。 帧指针充当被调用函数和调用函数之间的锚。 当调用一个函数时,该函数首先将fp 的当前值保存在堆栈上。 然后,它将sp 寄存器的值保存在fp 寄存器中。
以下为引用文章:
原地址:https://zhuanlan.zhihu.com/p/343563035
Go的汇编是基于 Plan9 的,我想是因为Ken Thompson(他是Plan 9操作系统的核心成员)吧。如果你不熟悉Plan 9,看到这段汇编可能比较懵。小菜刀觉得没必要花过多时间去学懂,因为它很复杂且另类,同时涉及到很多硬件知识。不过如果只是要求看懂简单的汇编代码,稍微研究下还是能够做到的。
由于本文的重点并不是plan 9,所以这里就只解释上述汇编代码的含义。

atomic.Cas(SB)的函数原型为func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool),其入参addr为8个字节(64位系统),old和new分别为4个字节,返回参数swapped为1个字节,所以17=8+4+4+1。
FP(Frame pointer: arguments and locals),它是伪寄存器,用来表示函数参数与局部变量。其通过symbol+offset(FP)的方式进行使用。在本函数中,我们可以把FP指向的内容表示为如下所示。

ptr+0(FP)代表的意思就是ptr从FP偏移0byte处取内容。AX,BX,CX在这里,知道它们是存放数据的寄存器即可。MOV X Y所做的操作是将X上的内容复制到Y上去,MOV后缀L表示“长字”(32位,4个字节),Q表示“四字”(64位,8个字节)。
重点来了,LOCK指令。这里参考 Intel 的64位和IA-32架构开发手册
Causes the processor’s LOCK# signal to be asserted during execution of the accompanying instruction (turns the instruction into an atomic instruction). In a multiprocessor environment, the LOCK# signal ensures that the processor has exclusive use of any shared memory while the signal is asserted.
在多处理器环境中,指令前缀LOCK能够确保,在执行LOCK随后的指令时,处理器拥有对任何共享内存的独占使用。
LOCK:是一个指令前缀,其后必须跟一条“读-改-写”性质的指令,它们可以是ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, XCHG。该指令是一种锁定协议,用于封锁总线,禁止其他 CPU 对内存的操作来保证原子性。
在汇编代码里给指令加上 LOCK 前缀,这是CPU 在硬件层面支持的原子操作。但这样的锁粒度太粗,其他无关的内存操作也会被阻塞,大幅降低系统性能,核数越多愈发显著。
为了提高性能,Intel 从 Pentium 486 开始引入了粒度较细的缓存锁:MESI协议(关于该协议,小菜刀在之前的文章《CPU缓存体系对Go程序的影响》有详细介绍过)。此时,尽管有LOCK前缀,但如果对应数据已经在 cache line里,也就不用锁定总线,仅锁住缓存行即可。
CMPXCHGL,L代表4个字节。该指令会把AX(累加器寄存器)中的内容(old)和第二个操作数(0(BX))中的内容(ptr所指向的数据)比较。如果相等,则把第一个操作数(CX)中的内容(new)赋值给第二个操作数。
这里,SETEQ 与CMPXCHGL是配合使用的,如果CMPXCHGL中比较结果是相等的,则设置ret(即函数原型中的swapped)为1,不等则设置为0。RET代表函数返回。
综上:
因此上面的函数中for循环是完全没有必要的直接去掉就行了改成: