atomic原子类实现机制_atomic实现原理
atomic是原子的意思,意味"不可分割"的整體。在Linux kernel中有一類atomic操作API。這些操作對(duì)用戶而言是原子執(zhí)行的,在一個(gè)CPU上執(zhí)行過程中,不會(huì)被其他CPU打斷。最常見的操作是原子讀改寫,簡稱RMW。例如,atomic_inc()接口。atomic硬件實(shí)現(xiàn)和Cache到底有什么關(guān)系呢?其實(shí)有一點(diǎn)關(guān)系,下面會(huì)一步步揭曉答案。
問題背景
我們先來看看不使用原子操作的時(shí)候,我們會(huì)遇到什么問題。我們知道increase一個(gè)變量,CPU微觀指令級(jí)別分成3步操作。1) 先read變量的值到CPU內(nèi)存寄存器;2) 對(duì)寄存器的值遞增;3) 將寄存器的值寫回變量。例如不使用原子指令的情況下在多個(gè)CPU上執(zhí)行以下increase函數(shù)。
int counter = 0;
void increase(void)
{
counter++;
}
例如2個(gè)CPU得系統(tǒng),初始值counter為0。在兩個(gè)CPU上同時(shí)執(zhí)行以上increase函數(shù)。可能出現(xiàn)如下操作序列:
+ +----------------------+----------------------+
| | CPU0 operation | CPU1 operation |
| +----------------------+----------------------+
| | read counter (== 0) | |
| +----------------------+----------------------+
| | increase | read counter (== 0) |
| +----------------------+----------------------+
| | write counter (== 1) | increase |
| +----------------------+----------------------+
| | | write counter (== 1) |
| +----------------------+----------------------+
V
timeline
我們可以清晰地看到,當(dāng)CPU0讀取counter的值位0后,在執(zhí)行increase操作的同時(shí),CPU1也讀取counter變量,同樣counter的值依然是0。隨后CPU0和CPU1先后將1的值寫入內(nèi)存。實(shí)際上,我們想執(zhí)行兩次increase操作,我應(yīng)該得到counter值為2。但是實(shí)際上得到的是1。這不是我們想要的結(jié)果。為了解決這個(gè)問題,硬件引入原子自增指令。保證CPU0遞增原子變量counter之間,不被其他CPU執(zhí)行自增指令導(dǎo)致不想要的結(jié)果。硬件是如何實(shí)現(xiàn)原子操作期間不被打斷呢?
Bus Lock
當(dāng)CPU發(fā)出一個(gè)原子操作時(shí),可以先鎖住Bus(總線)。這樣就可以防止其他CPU的內(nèi)存操作。等原子操作結(jié)束,釋放Bus。這樣后續(xù)的內(nèi)存操作就可以進(jìn)行。這個(gè)方法可以實(shí)現(xiàn)原子操作,但是鎖住Bus會(huì)導(dǎo)致后續(xù)無關(guān)內(nèi)存操作都不能繼續(xù)。實(shí)際上,我們只關(guān)心我們操作的地址數(shù)據(jù)。只要我們操作的地址鎖住即可,而其他無關(guān)的地址數(shù)據(jù)訪問依然可以繼續(xù)。所以我們引入另一種解決方法。
Cacheline Lock
為了實(shí)現(xiàn)多核Cache一致性,現(xiàn)在的硬件基本采用MESI協(xié)議(或者M(jìn)ESI變種)維護(hù)一致性。因此我們可以借助多核Cache一致性協(xié)議MESI實(shí)現(xiàn)原子操作。我們知道Cache line的狀態(tài)處于Exclusive或者M(jìn)odified時(shí),可以說明該變量只有當(dāng)前CPU私有Cache緩存了該數(shù)據(jù)。所以我們可以直接修改Cache line即可更新數(shù)據(jù)。并且MESI協(xié)議可以幫我們保證互斥。當(dāng)然這不能不能保證RMW操作期間不被打斷,因此我們還需要做些手腳實(shí)現(xiàn)原子操作。
我們依然假設(shè)只有2個(gè)CPU的系統(tǒng)。當(dāng)CPU0試圖執(zhí)行原子遞增操作時(shí)。a) CPU0發(fā)出"Read Invalidate"消息,其他CPU將原子變量所在的緩存無效,并從Cache返回?cái)?shù)據(jù)。CPU0將Cache line置成Exclusive狀態(tài)。然后將該cache line標(biāo)記locked。b) 然后CPU0讀取原子變量,修改,最后寫入cache line。c) 將cache line置位unlocked。
在步驟a)和c)之間,如果其他CPU(例如CPU1)嘗試執(zhí)行一個(gè)原子遞增操作,CPU1會(huì)發(fā)送一個(gè)"Read Invalidate"消息,CPU0收到消息后,檢查對(duì)應(yīng)的cache line的狀態(tài)是locked,暫時(shí)不回復(fù)消息(CPU1會(huì)一直等待CPU0回復(fù)Invalidate Acknowledge消息)。直到cache line變成unlocked。這樣就可以實(shí)現(xiàn)原子操作。我們稱這種方式為鎖cache line。這種實(shí)現(xiàn)方式必須要求操作的變量位于一個(gè)cache line。
LL/SC
LL/SC(Load-Link/Store-Conditional)是另一種硬件實(shí)現(xiàn)方法。例如aarch64架構(gòu)就采用這種方法。這種方法就不是我們關(guān)注的重點(diǎn)了。略過。
總結(jié)
借助多核Cache一致性協(xié)議可以很方便實(shí)現(xiàn)原子操作。當(dāng)然遠(yuǎn)不止上面舉例說的atomic_inc還有很多其他類似的原子操作,例如原子比較交換等。
總結(jié)
以上是生活随笔為你收集整理的atomic原子类实现机制_atomic实现原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MATLAB三元条件运算符,C++ ?:
- 下一篇: 条件运算符用法