目錄
前言" >前言
#快取一致性" >#快取一致性
順序一致性" >順序一致性
記憶體屏障" >記憶體屏障
多處理器間同步" >多處理器間同步
内存屏障的实现" >内存屏障的实现
首頁 系統教程 Linux 詳解Linux核心中的記憶體屏障

詳解Linux核心中的記憶體屏障

Feb 10, 2024 pm 03:00 PM
linux linux教程 linux系統 linux指令 shell腳本 嵌入式linux linux入門 linux學習

前言

我之前閱讀了一篇關於順序一致性和快取一致性的討論文章,對於這兩個概念的區別和聯繫有了更加清晰的認識。在Linux核心中,有許多同步和屏障機制,我想在此做一些總結。

詳解Linux核心中的記憶體屏障

#快取一致性

之前我一直認為Linux中的許多機制是為了保證快取一致性,但實際上,絕大部分的快取一致性是由硬體機制實現的。只有在使用帶有lock前綴的指令時,才與緩存有些關係(雖然這話絕對並不嚴謹,但是從目前來看,大多數情況下是如此的)。我們更多的時候,是為了確保順序​​一致性。

快取一致性是指在多處理器系統中,每個CPU都有自己的L1快取。由於不同CPU的L1快取中可能快取了同一片記憶體的內容,當一個CPU更改了自己被快取的內容時,它必須確保另一個CPU讀取這塊資料時也能夠讀取到最新的內容。但是,別擔心,這個複雜的工作完全由硬體來完成,透過實作MESI協議,硬體可以輕鬆地完成快取一致性的工作。即使是多個CPU同時寫入,也不會有問題。無論是在自己的快取中、其他CPU的快取中或記憶體中,一個CPU總是能夠讀入最新的數據,這就是快取一致性的工作原理。

順序一致性

#所謂順序一致性,說的則是與快取一致性完全不同的概念,雖然它們都是處理器發展的產物。因為編譯器的技術不斷發展,它可能為了最佳化你的程式碼,而將某些操作的順序變更執行。處理器中也早就有了多發射、亂序執行的概念。這樣的結果,就是實際執行的指令順序會與程式設計時程式碼的執行順序略有不同。這在單處理器下當然沒什麼,畢竟只要自己的程式碼不過問,就沒人過問,編譯器和處理器就是在保證自己的程式碼發現不了的情況下打亂執行順序的。但多處理器不是這樣,可能一個處理器上指令的完成順序,會對其它處理器上執行的程式碼造成很大影響。所以就有了順序一致性的概念,就是保證一個處理器上執行緒的執行順序,在其它的處理器上的執行緒看來,都是一樣的。這個問題的解決不是光靠處理器或編譯器就能解決的,需要軟體的介入。

記憶體屏障

軟體介入的方式也非常簡單,那就是插入記憶體屏障(memory barrier)。其實記憶體屏障這個詞,是搞處理器的人造的,弄得我們很不好理解。記憶體屏障,很容易讓我們串到快取一致性去,乃至懷疑是否這樣做才能讓它cpu看到被修改過的cache,這樣想就錯了。所謂記憶體屏障,從處理器角度來說,是用來串列化讀寫操作的,從軟體角度來講,就是用來解決順序一致性問題的。編譯器不是要打亂程式碼執行順序嗎,處理器不是要亂序執行嗎,你插入一個記憶體屏障,就等於告訴編譯器,屏障前後的指令順序不能顛倒,告訴處理器,只有等屏障前的指令執行完了,屏障後的指令才能開始執行。當然,記憶體屏障能阻擋編譯器亂來,但處理器還是有辦法。處理器中不是有多發射、亂序執行、順序完成的概念嗎,它在內存屏障時只要保證前面指令的讀寫操作,一定在後面指令的讀寫操作完成之前完成,就可以了。所以記憶體屏障才會對應有讀屏障、寫屏障和讀寫屏障三類。如x86之前保證寫入操作都是順序完成的,所以不需要寫屏障,但現在也有部分ia32處理器的寫入操作變成亂序完成,所以也需要寫屏障。
其實,除了專門的讀寫屏障指令,還有很多指令的執行是帶有讀寫屏障功能的,例如帶有lock前綴的指令。在專門的讀寫屏障指令出現之前,linux就是靠lock撐過來的。
至於在那裡插入讀寫屏障,則視軟體的需求而定。讀寫屏障無法完全實現順序一致性,但多處理器上的線程也不會一直盯著你的執行順序看,只要保證在它看過的時候,認為你符合順序一致性,執行不會出現你程式碼中沒有預料到的情況。所謂預料外的情況,舉例而言,你的線程是先給變量a賦值,再給變量b賦值,結果別的處理器上運行的線程看過來,發現b賦值了,a卻沒有賦值,(注意這種不一致不是快取不一致造成的,而是處理器寫入作業完成的順序不一致所造成的),這時就要在a賦值與b賦值之間,加上一個寫入屏障。

多處理器間同步

#有了SMP之後,執行緒就開始同時在多個處理器上運作。只要是線程就有通訊和同步的要求。幸好SMP系統是共享記憶體的,也就是所有處理器看到的記憶體內容都一樣,雖然有獨立的L1 cache,但還是由硬體完成了快取一致性處理的問題。那不同處理器上的執行緒要存取相同數據,需要臨界區,需要同步。靠什麼同步?之前在UP系統中,我們上靠信號量,下靠關中斷和讀取修改寫指令。現在在SMP系統中,關卡中斷已經廢了,雖然為了同步同一處理器上的執行緒還是需要的,但只靠它已經不行了。讀修改寫指令?也不行了。在你指令中讀取操作完成寫入操作還沒進行時,就可能有另外的處理器進行了讀取操作或寫入操作。快取一致性協定是先進,但還沒先進到預測這條讀取操作是哪一種指令發出來的。所以x86又發明了帶有lock前綴的指令。在此指令執行時,會將所有包含指令中讀寫位址的cache line失效,並鎖定記憶體匯流排。這樣別的處理器要想對同樣的位址或同一個cache line上的位址讀寫,既無法從cache中進行(cache中相關line已經失效了),也無法從記憶體匯流排上進行(整個記憶體匯流排都鎖了),終於達到原子性執行的目的了。當然,從P6處理器開始,如果帶lock前綴指令要存取的位址本來就在cache中,就不需要鎖記憶體匯流排,也能完成原子性操作了(雖然我懷疑這是因為加了多處理器內部公共的L2 cache的緣故)。

因為會鎖定記憶體匯流排,所以帶lock前綴指令執行前,也會先將未完成的讀寫操作完成,也起到記憶體屏障的功能。
現在多處理器間執行緒的同步,上用自旋鎖,下用這種帶了lock前綴的讀取修改寫指令。當然,實際的同步還有加上禁止本處理器任務調度的,有加上任務關中斷的,還會在外面加上信號量的外衣。 linux中對這種自旋鎖的實現,已歷經四代發展,變得愈發高效強大。

内存屏障的实现

\#ifdef CONFIG_SMP  
\#define smp_mb()  mb()  
\#define smp_rmb()  rmb()  
\#define smp_wmb()  wmb()  
\#else  
\#define smp_mb()  barrier()  
\#define smp_rmb()  barrier()  
\#define smp_wmb()  barrier()  
\#endif 
登入後複製

CONFIG_SMP就是用来支持多处理器的。如果是UP(uniprocessor)系统,就会翻译成barrier()。

#define barrier() asm volatile(“”: : :”memory”)
barrier()的作用,就是告诉编译器,内存的变量值都改变了,之前存在寄存器里的变量副本无效,要访问变量还需再访问内存。这样做足以满足UP中所有的内存屏障。

\#ifdef CONFIG_X86_32  
/* 
 \* Some non-Intel clones support out of order store. wmb() ceases to be a 
 \* nop for these. 
 */  
\#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)  
\#define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2)  
\#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)  
\#else  
\#define mb()  asm volatile("mfence":::"memory")  
\#define rmb()  asm volatile("lfence":::"memory")  
\#define wmb()  asm volatile("sfence" ::: "memory")  
\#endif 
登入後複製

如果是SMP系统,内存屏障就会翻译成对应的mb()、rmb()和wmb()。这里CONFIG_X86_32的意思是说这是一个32位x86系统,否则就是64位的x86系统。现在的linux内核将32位x86和64位x86融合在同一个x86目录,所以需要增加这个配置选项。

可以看到,如果是64位x86,肯定有mfence、lfence和sfence三条指令,而32位的x86系统则不一定,所以需要进一步查看cpu是否支持这三条新的指令,不行则用加锁的方式来增加内存屏障。

SFENCE,LFENCE,MFENCE指令提供了高效的方式来保证读写内存的排序,这种操作发生在产生弱排序数据的程序和读取这个数据的程序之间。 
  SFENCE——串行化发生在SFENCE指令之前的写操作但是不影响读操作。 
  LFENCE——串行化发生在SFENCE指令之前的读操作但是不影响写操作。 
  MFENCE——串行化发生在MFENCE指令之前的读写操作。 
sfence:在sfence指令前的写操作当必须在sfence指令后的写操作前完成。 
lfence:在lfence指令前的读操作当必须在lfence指令后的读操作前完成。 
mfence:在mfence指令前的读写操作当必须在mfence指令后的读写操作前完成。
登入後複製

至于带lock的内存操作,会在锁内存总线之前,就把之前的读写操作结束,功能相当于mfence,当然执行效率上要差一些。

说起来,现在写点底层代码真不容易,既要注意SMP问题,又要注意cpu乱序读写问题,还要注意cache问题,还有设备DMA问题,等等。

多处理器间同步的实现
多处理器间同步所使用的自旋锁实现,已经有专门的文章介绍

以上是詳解Linux核心中的記憶體屏障的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

vscode需要什麼電腦配置 vscode需要什麼電腦配置 Apr 15, 2025 pm 09:48 PM

VS Code 系統要求:操作系統:Windows 10 及以上、macOS 10.12 及以上、Linux 發行版處理器:最低 1.6 GHz,推薦 2.0 GHz 及以上內存:最低 512 MB,推薦 4 GB 及以上存儲空間:最低 250 MB,推薦 1 GB 及以上其他要求:穩定網絡連接,Xorg/Wayland(Linux)

Linux體系結構:揭示5個基本組件 Linux體系結構:揭示5個基本組件 Apr 20, 2025 am 12:04 AM

Linux系統的五個基本組件是:1.內核,2.系統庫,3.系統實用程序,4.圖形用戶界面,5.應用程序。內核管理硬件資源,系統庫提供預編譯函數,系統實用程序用於系統管理,GUI提供可視化交互,應用程序利用這些組件實現功能。

notepad怎麼運行java代碼 notepad怎麼運行java代碼 Apr 16, 2025 pm 07:39 PM

雖然 Notepad 無法直接運行 Java 代碼,但可以通過借助其他工具實現:使用命令行編譯器 (javac) 編譯代碼,生成字節碼文件 (filename.class)。使用 Java 解釋器 (java) 解釋字節碼,執行代碼並輸出結果。

vscode終端使用教程 vscode終端使用教程 Apr 15, 2025 pm 10:09 PM

vscode 內置終端是一個開發工具,允許在編輯器內運行命令和腳本,以簡化開發流程。如何使用 vscode 終端:通過快捷鍵 (Ctrl/Cmd ) 打開終端。輸入命令或運行腳本。使用熱鍵 (如 Ctrl L 清除終端)。更改工作目錄 (如 cd 命令)。高級功能包括調試模式、代碼片段自動補全和交互式命令歷史。

git怎麼查看倉庫地址 git怎麼查看倉庫地址 Apr 17, 2025 pm 01:54 PM

要查看 Git 倉庫地址,請執行以下步驟:1. 打開命令行並導航到倉庫目錄;2. 運行 "git remote -v" 命令;3. 查看輸出中的倉庫名稱及其相應的地址。

vscode在哪寫代碼 vscode在哪寫代碼 Apr 15, 2025 pm 09:54 PM

在 Visual Studio Code(VSCode)中編寫代碼簡單易行,只需安裝 VSCode、創建項目、選擇語言、創建文件、編寫代碼、保存並運行即可。 VSCode 的優點包括跨平台、免費開源、強大功能、擴展豐富,以及輕量快速。

Linux的主要目的是什麼? Linux的主要目的是什麼? Apr 16, 2025 am 12:19 AM

Linux的主要用途包括:1.服務器操作系統,2.嵌入式系統,3.桌面操作系統,4.開發和測試環境。 Linux在這些領域表現出色,提供了穩定性、安全性和高效的開發工具。

vscode 可以用於 mac 嗎 vscode 可以用於 mac 嗎 Apr 15, 2025 pm 07:36 PM

VS Code 可以在 Mac 上使用。它具有強大的擴展功能、Git 集成、終端和調試器,同時還提供了豐富的設置選項。但是,對於特別大型項目或專業性較強的開發,VS Code 可能會有性能或功能限制。

See all articles