最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

淺淺講解原子操作和內(nèi)存屏障

2022-10-10 16:42 作者:補給站Linux內(nèi)核  | 我要投稿

若干匯編語言指令具有”讀—修改—寫”類型----也就是說,它們訪問存儲器單元兩次,第一次讀原值,第二次寫新值。

假定運行在兩個CPU上的兩個內(nèi)核控制路徑試圖通過執(zhí)行非原子操作來同時” 讀—修改—寫”同一存儲器單元。首先,兩個CPU都試圖讀同一單元,但是存儲器仲裁器插入,只允許其中的一個訪問而讓另一個延遲。然而,當?shù)谝粋€讀操作已經(jīng)完成后,延遲的CPU從那個存儲器單元正好讀到同一個值。然后,兩個CPU都試圖向那個存儲器單元寫一新值,總線存儲器訪問再一次被存儲器仲裁器串行化,最終,兩個寫操作都成功。但是,全局的結果是不對的,因為兩個CPU寫入同一值。因此,兩個交錯的” 讀—修改—寫”操作成了一個單獨的操作。

避免由于” 讀—修改—寫”指令引起的競爭條件是最容易的辦法,就是確保這樣的操作在芯片級是原子的。任何一個這樣的操作都必須以單個指令執(zhí)行,中間不能中斷,且避免其它的CPU訪問同一存儲器單元。這些很小的原子操作可以建立在其它更靈活機制的基礎之上以創(chuàng)建臨界區(qū)。


讓我們根據(jù)那個分類來回顧一下80x86的指令:

(1) 進行零次或一次對齊內(nèi)存訪問的匯編指令是原子的。

(2) 如果在讀操作之后、寫操作之前沒有其它處理器占用內(nèi)存總線,那么從內(nèi)存中讀取數(shù)據(jù)、更新數(shù)據(jù)并把更新后的數(shù)據(jù)寫回內(nèi)存中的這些” 讀—修改—寫”匯編語言指令是原子的。當然,在單處理器系統(tǒng)中,永遠都不會發(fā)生內(nèi)存總線竊用的情況。

(3) 操作碼前緣是lock字節(jié)的” 讀—修改—寫”匯編語言指令即使在多處理器系統(tǒng)中也是原子的。當控制單元檢測到這個前綴時,就”鎖定”內(nèi)存總線,直到這條指令執(zhí)行完成為止。因此,當加鎖的指令執(zhí)行時,其它處理器不能訪問這個內(nèi)存單元。

(4) 操作碼前綴是一個rep字節(jié)的匯編語言指令不是原子的,這條指令強行讓控制單元多次重復執(zhí)行相同的指令??刂茊卧趫?zhí)行新的循環(huán)之前要檢查掛起的中斷。

在你編寫C代碼程序時,并不能保證編譯器會為a=a+1或甚至像a++這樣的操作使用一個原子指令。因此,Linux內(nèi)核提供了一個專門的atomic_c類型和一些專門的函數(shù)和宏(參見表5-4),這些函數(shù)和宏作用于atomic_t類型的變量,并當作單獨的、原子的匯編語言指令來使用。在多處理器系統(tǒng)中,每條這樣的指令都有一個lock字節(jié)的前綴。


【文章福利】小編推薦自己的Linux內(nèi)核技術交流群:【891587639】整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)? ? ?

優(yōu)化和內(nèi)存屏障

當使用優(yōu)化的編譯器時,你千萬不要認為指令會嚴格按它們在源代碼中出現(xiàn)的順序執(zhí)行。例如,編譯器可能重新安排匯編語言指令以寄存器以最優(yōu)的方式使用。此外,現(xiàn)代CPU通常并行地執(zhí)行若干條指令,且可能重俗人安排內(nèi)存訪問。這種重新排序可以極大地加速程序的執(zhí)行。

然而,當處理同步時,必須避免指令重新排序。如果放在同步原語之后的一條指令在同步原語之前執(zhí)行,事情很快就會變得失控。事實上,所有的同步原語起優(yōu)化和內(nèi)存屏障的作用。

優(yōu)化屏障原語保證編譯程序不會混淆放在原語操作之前的匯編語言指令和放在原語操作之后的匯編語言指令,這些匯編語言指令在C中都有對應的語句。在Linux中,優(yōu)化屏蔽就是barrier()宏,它展開為asm volatile(“”:::”memory”)。指令asm告訴編譯程序要插入?yún)R編語言片段。volatile關鍵字禁止編譯器把asm指令與程序中的其它指令重新組合。memory關鍵字強制編譯器貧富RAM中的所有內(nèi)存單元已經(jīng)被匯編語言指令修改;因此,編譯器不能使用存放在CPU寄存器中的內(nèi)存的值來優(yōu)化asm指令前的代碼。注意,優(yōu)化屏障并不保證不使當前CPU把匯編語言指令混在一起執(zhí)行------這是內(nèi)存屏障的工作。

內(nèi)存屏障原主確保,在原語之后的操作開始執(zhí)行之前,原語之前的操作已經(jīng)完成。因此,內(nèi)存屏障類似于防火墻,讓任何匯編語言指令都不能通過。

在80x86處理器中,下列種類的匯編語言指令是”串行的”,因為它們起內(nèi)存屏障的作用:

(1) 對I/O端口進行操作的所有指令。

(2) 有l(wèi)ock前緣的所有指令。

(3) 寫控制寄存器、系統(tǒng)寄存器或調(diào)試寄存器的所有指令。

(4) 在Pentium 4微處理器中引入的匯編語言指令lfence,sfence和mfence,它們分別有效地實現(xiàn)讀內(nèi)存屏障、寫內(nèi)存屏障和讀-寫內(nèi)存屏障。

(5) 少數(shù)專門的匯編語言指令,終止中斷處理程序或異常處理程序的iret指令就是其中的一個。

Linux使用六個內(nèi)存屏障原語,如表5-6所示。這些原語也被當作優(yōu)化屏障,因為我們必須保證編譯程序不在屏障前后移動匯編語言指令?!弊x內(nèi)存屏障”僅僅作用于從內(nèi)存讀的指令,而”寫內(nèi)存屏障”僅僅作用于寫內(nèi)存的指令。內(nèi)存屏障既用于多處理器系統(tǒng),也用于單處理器系統(tǒng)。當內(nèi)存屏障應該防止僅出現(xiàn)于多處理器系統(tǒng)上的競爭條件時,就使用smp_xxx()原語;在單處理器系統(tǒng)上,它們什么也不做。其它的內(nèi)存屏障防止出現(xiàn)在單處理器和多處理器系統(tǒng)上的競爭條件。

內(nèi)存屏障原語的實現(xiàn)依賴于系統(tǒng)的體系結構。在80x86微處理器上,如果CPU支持lfence匯編語言指令,就把rmb()宏展開為asm volatile(“l(fā)fence”),否則就展開為asm volatile(“l(fā)ock;adl $0,0(%%esp)”:::”memory”)。asm指令告訴編譯器插入一些匯編語言指令并起優(yōu)化屏障的作用?!發(fā)ock;adl $0,0(%%esp)匯編指令把0加到棧頂?shù)膬?nèi)存單元;這條指令本身沒有價值,但是,lock前綴使得這條指令成為CPU的一個內(nèi)存屏障。

Intel上的wmb()宏實際上更簡單,因為它展開為barrier()。這是因為Intel處理器從不對寫內(nèi)存訪問重新排序,因此,沒有必要在代碼中插入一條串行化匯編指令。不過,這個宏禁止編譯器重新組合指令。

注意,在多處理器系統(tǒng)上,在前一節(jié)”原子操作”中描述的所有原子操作都起內(nèi)存屏障的作用,因為它們使用了lock字節(jié)。






淺淺講解原子操作和內(nèi)存屏障的評論 (共 條)

分享到微博請遵守國家法律
电白县| 长武县| 应城市| 夹江县| 江西省| 大洼县| 湖口县| 昌乐县| 宝应县| 邵东县| 平南县| 宁明县| 县级市| 廊坊市| 西丰县| 通化市| 姜堰市| 金坛市| 牡丹江市| 九台市| 明水县| 鹤岗市| 阳信县| 阳朔县| 安塞县| 红安县| 犍为县| 望江县| 高雄市| 九台市| 双桥区| 运城市| 邵武市| 商水县| 辰溪县| 莆田市| 宁海县| 金门县| 云霄县| 德昌县| 台东市|