Go語(yǔ)言atomic包CompareAndSwapInt32函數(shù)
請(qǐng)說(shuō)明下面代碼書(shū)寫(xiě)是否正確?
看到上面最重點(diǎn)的是要理解函數(shù):atomic.CompareAndSwapInt32
點(diǎn)擊這個(gè)函數(shù)找到:

之后找到這個(gè)函數(shù)實(shí)現(xiàn):

之后找到這個(gè)匯編函數(shù):

這邊先將一些匯編基礎(chǔ)指令意思貼出來(lái):


寄存器fp(frame pointer)?用作幀指針。 幀指針充當(dāng)被調(diào)用函數(shù)和調(diào)用函數(shù)之間的錨。 當(dāng)調(diào)用一個(gè)函數(shù)時(shí),該函數(shù)首先將fp 的當(dāng)前值保存在堆棧上。 然后,它將sp 寄存器的值保存在fp 寄存器中。
以下為引用文章:
原地址:https://zhuanlan.zhihu.com/p/343563035
Go的匯編是基于?Plan9?的,我想是因?yàn)镵en Thompson(他是Plan 9操作系統(tǒng)的核心成員)吧。如果你不熟悉Plan 9,看到這段匯編可能比較懵。小菜刀覺(jué)得沒(méi)必要花過(guò)多時(shí)間去學(xué)懂,因?yàn)樗軓?fù)雜且另類(lèi),同時(shí)涉及到很多硬件知識(shí)。不過(guò)如果只是要求看懂簡(jiǎn)單的匯編代碼,稍微研究下還是能夠做到的。
由于本文的重點(diǎn)并不是plan 9,所以這里就只解釋上述匯編代碼的含義。

atomic.Cas(SB)的函數(shù)原型為func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool),其入?yún)ddr為8個(gè)字節(jié)(64位系統(tǒng)),old和new分別為4個(gè)字節(jié),返回參數(shù)swapped為1個(gè)字節(jié),所以17=8+4+4+1。
FP(Frame pointer: arguments and locals),它是偽寄存器,用來(lái)表示函數(shù)參數(shù)與局部變量。其通過(guò)symbol+offset(FP)的方式進(jìn)行使用。在本函數(shù)中,我們可以把FP指向的內(nèi)容表示為如下所示。

ptr+0(FP)代表的意思就是ptr從FP偏移0byte處取內(nèi)容。AX,BX,CX在這里,知道它們是存放數(shù)據(jù)的寄存器即可。MOV X Y所做的操作是將X上的內(nèi)容復(fù)制到Y(jié)上去,MOV后綴L表示“長(zhǎng)字”(32位,4個(gè)字節(jié)),Q表示“四字”(64位,8個(gè)字節(jié))。
重點(diǎn)來(lái)了,LOCK指令。這里參考 Intel 的64位和IA-32架構(gòu)開(kāi)發(fā)手冊(cè)
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.
在多處理器環(huán)境中,指令前綴LOCK能夠確保,在執(zhí)行LOCK隨后的指令時(shí),處理器擁有對(duì)任何共享內(nèi)存的獨(dú)占使用。
LOCK:是一個(gè)指令前綴,其后必須跟一條“讀-改-寫(xiě)”性質(zhì)的指令,它們可以是ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, XCHG。該指令是一種鎖定協(xié)議,用于封鎖總線,禁止其他 CPU 對(duì)內(nèi)存的操作來(lái)保證原子性。
在匯編代碼里給指令加上 LOCK 前綴,這是CPU 在硬件層面支持的原子操作。但這樣的鎖粒度太粗,其他無(wú)關(guān)的內(nèi)存操作也會(huì)被阻塞,大幅降低系統(tǒng)性能,核數(shù)越多愈發(fā)顯著。
為了提高性能,Intel 從 Pentium 486 開(kāi)始引入了粒度較細(xì)的緩存鎖:MESI協(xié)議(關(guān)于該協(xié)議,小菜刀在之前的文章《CPU緩存體系對(duì)Go程序的影響》有詳細(xì)介紹過(guò))。此時(shí),盡管有LOCK前綴,但如果對(duì)應(yīng)數(shù)據(jù)已經(jīng)在 cache line里,也就不用鎖定總線,僅鎖住緩存行即可。
CMPXCHGL,L代表4個(gè)字節(jié)。該指令會(huì)把AX(累加器寄存器)中的內(nèi)容(old)和第二個(gè)操作數(shù)(0(BX))中的內(nèi)容(ptr所指向的數(shù)據(jù))比較。如果相等,則把第一個(gè)操作數(shù)(CX)中的內(nèi)容(new)賦值給第二個(gè)操作數(shù)。
這里,SETEQ?與CMPXCHGL是配合使用的,如果CMPXCHGL中比較結(jié)果是相等的,則設(shè)置ret(即函數(shù)原型中的swapped)為1,不等則設(shè)置為0。RET代表函數(shù)返回。
綜上:
因此上面的函數(shù)中for循環(huán)是完全沒(méi)有必要的直接去掉就行了改成: