處理器如何實現原子操作

2021-10-10 23:53:18 字數 3456 閱讀 7828

三、多核原子操作

cas原子(atomic):是「不能被進一步分割的最小粒子」,而原子操作(atomic operation)意為「不可被中斷的乙個或一系列操作」。

併發:單核cpu上,當多個執行緒在在操作時,把cpu執行時間劃分為若干時間段,再將時間段分配給各個執行緒執行,在乙個時間段的執行緒**執行時,其他執行緒處於掛起狀態。

並行:多核cpu上,當乙個核心處理器執行乙個執行緒時,另乙個核心處理器可以同時個執行緒。

總結

單cpu計算機中程序只能是併發,多cpu計算機中程序可以並行。

單cpu單核計算機中線程只能併發,單cpu多核計算機中線程可以並行。

c語言語句「count++;」在未經編譯器優化時生成的彙編**為。

當作業系統內存在多個程序同時執行這段**時,就可能帶來併發問題。

假設count變數初始值為0。程序1執行完「mov eax, [count]」後,暫存器eax內儲存了count的值0。此時,程序2被排程執行,搶占了程序1的cpu的控制權。程序2執行「count++;」的彙編**,將累加後的count值1寫回到記憶體。然後,程序1再次被排程執行,cpu控制權回到程序1。程序1接著執行,計算count的累加值仍為1,寫回到記憶體。雖然程序1和程序2執行了兩次「count++;」操作,但是count實際的記憶體值為1,而不是2!

解決這個問題的方法是,將「count++;」語句翻譯為單指令操作:

intel x86指令集支援記憶體運算元的inc操作,這樣「count++;」操作可以在一條指令內完成。因為程序的上下文切換是在總是在一條指令執行完成後,所以不會出現上述的併發問題。對於單處理器來說,一條處理器指令就是乙個原子操作。

在多處理器的環境下,例如smp架構,這個結論不再成立。我們知道「inc [count]」指令的執行過程分為三步:

1)從記憶體將count的資料讀取到cpu。

2)累加讀取的值。

3)將修改的值寫回count記憶體。

這又回到前面併發問題類似的情況,只不過此時併發的主題不再是程序,而是處理器。

核心1核心1

mov eax,[count]

處理處理

mov eax,[count]

處理inc eax

處理mov [count],eax

inc eax

處理mov [count],eax

處理intel x86指令集提供了指令字首lock用於鎖定前端序列匯流排(fsb),保證了指令執行時不會受到其他處理器的干擾。

使用lock指令字首後,處理器間對count記憶體的併發訪問(讀/寫)被禁止,從而保證了指令的原子性。當乙個cpu核執行乙個執行緒去訪問資料做操作的時候,它會向匯流排上傳送乙個lock訊號,此時其他的執行緒想要去請求主記憶體的時候,就會被阻塞,這樣該處理器核心就可以獨享這個共享記憶體,而且釋放鎖後,會呼叫smp_mb invalide,使其他核心的快取失效。

一般而言,從高層往底層走,儲存裝置變得更慢、更便宜和更大。在最高層(l0),是少量快速的cpu暫存器,cpu可以在乙個時鐘週期內訪問它們。接下來是乙個或多個小型到中興的基於sram的快取記憶體儲存器,可以在幾個cpu時鐘週期內訪問它們。然後是乙個大的基於dram的主存,可以在幾十到幾百個時鐘週期內訪問它們。接下來是慢速但容量很大的本地磁碟。最後,有些系統甚至包括了一層附加的遠端伺服器上的磁碟,要通過網路來訪問他們。

在多核cpu中,每個核心(core)獨享l0、l1、l2儲存器,共享其他的儲存器。

由於存在快取區,有可能出現快取區資料不一致的情況。例如,有乙個變數a=0,現在起兩個執行緒都對變數a執行加一操作,假如兩個執行緒分別在兩個核心執行,開始時兩個核心都把a的值0存到了自己的快取中。執行緒1從自己的快取區讀取a的值0,加1後寫入主記憶體。執行緒2也是從自己的快取區讀取a的值0,加1後寫入主記憶體。最後a的值是1,而不是2。

當某核心對其快取中的資料進行了操作之後,就通知其他核心放棄儲存在它們內部的對應的快取,或者從主記憶體中重新讀取此資料。快取一致性主要是通過mesi協議實現

mesi協議

mesi:快取行(快取的基本單位,在intel的cpu上一般為64位元組)的4種狀態(modified、exclusive、 share or invalid)的縮寫。該協議要求在每個快取行上維護兩個狀態位,使得每個資料單位可能處於m、e、s和i這四種狀態之一,協議各種狀態含義如下:

m:被修改的。處於這一狀態的資料,只在本cpu中有快取資料,而其他cpu中沒有。同時其狀態相對於記憶體中的值來說,是已經被修改的,且沒有更新到記憶體中。

e:獨佔的。處於這一狀態的資料,只有在本cpu中有快取,且其資料沒有修改,即與記憶體中一致。

s:共享的。處於這一狀態的資料在多個cpu中都有快取,且與記憶體一致。

i:無效的。本cpu中的這份快取已經無效

每個core的cache控制器不僅知道自己的讀寫操作,也監聽其它cache的讀寫操作,核心的讀取會遵循幾個原則:

乙個處於m狀態的快取行,必須時刻監聽所有試圖讀取該快取行對應的主存位址的操作,如果監聽到,則必須在此操作執行前把其快取行中的資料寫回主記憶體。

乙個處於s狀態的快取行,必須時刻監聽使該快取行無效或者獨享該快取行的請求,如果監聽到,則必須把其快取行狀態設定為i。

乙個處於e狀態的快取行,必須時刻監聽其他試圖讀取該快取行對應的主存位址的操作,如果監聽到,則必須把其快取行狀態設定為s。

當核心需要讀取資料時,圖見下方,如果其快取行的狀態是i的,則需要從記憶體中讀取,並把自己狀態變成s,如果不是i,則可以直接讀取快取中的值,但在此之前,必須要等待其他cpu的監聽結果,如其他cpu也有該資料的快取且狀態是m,則需要等待其把快取更新到記憶體之後,再讀取。

當核心需要寫資料時,只有在其快取行是m或者e的時候才能執行,否則需要發出特殊的rfo指令(read or ownership,這是一種匯流排事務),通知其他核心置快取無效(i),這種情況下效能開銷是相對較大的。在寫入完成後,修改其快取狀態為m。

ps:並非所有情況都會使用快取一致性的,

被操作的資料不能被快取在處理器內部或運算元據跨越多個快取行,處理器會呼叫匯流排鎖定

有些處理器不支援快取行鎖定,只能用匯流排鎖定,比如說奔騰486以及更老的cpu

cas(compare and swap),cas記錄原來記憶體中的值old,和將要修改的值new。cas會檢測現在記憶體中的值now,如果now和old一致,則說明沒有別的cpu進行了記憶體修改,執行new值的更新。如果new和old值不等,則說明值已被修改,丟棄new值。

鎖 無鎖 多處理器程式設計 2 原子操作

原子操作是不可分割的操作,在執行完畢時它不會被任何事件中斷,原子操作是多數無鎖程式設計的基本前提。atomic是原子的意思,意味 不可分割 的整體。在linux kernel中有一類atomic操作api。這些操作對使用者而言是原子執行的,在乙個cpu上執行過程中,不會被其他cpu打斷。最常見的操作...

hbase 協處理器操作

建立表 create guanzhu cf1 create fensi cf1 測試插入資料 put guanzhu g cf1 from j put fensi b cf1 from a 上傳jar包到hdfs hadoop fs mkdir input hadoop fs put myhbase...

物理處理器與邏輯處理器

記錄解決方案,自己實際處理過,方案可用,在自己的部落格中記錄一下。cpu central processing unit 是 處理單元,本文介紹物理cpu,物理cpu核心,邏輯cpu,以及他們三者之間的關係。乙個物理cpu可以有1個或者多個物理核心,乙個物理核心可以作為1個或者2個邏輯cpu。物理c...