簡體   English   中英

GCC內存屏障__sync_synchronize vs asm volatile(“”:::“memory”)

[英]GCC memory barrier __sync_synchronize vs asm volatile(“”: : :“memory”)

asm volatile("": : :"memory")通常用作內存屏障(例如,在Linux內核barrier宏中看到)。

這聽起來類似於GCC內置__sync_synchronize所做的__sync_synchronize

這兩個相似嗎?

如果沒有,有什么區別,何時使用另一個?

有一個顯着的區別 - 第一個選項(內聯asm)在運行時實際上什么也沒做,那里沒有執行命令,CPU也不知道它。 它只在編譯時服務,告訴編譯器不要在此點(任何方向)上移動加載或存儲作為其優化的一部分。 它被稱為SW屏障。

第二個屏障(內置同步)將簡單地轉換為硬件屏障,如果您使用的是x86,則可能是圍欄(mfence / sfence)操作,或者其他架構中的等效操作。 CPU也可以在運行時進行各種優化,最重要的是實際執行無序操作 - 該指令告訴它確保加載或存儲不能通過這一點,並且必須在正確的一側觀察同步點。

這是另一個很好的解釋:

內存障礙的類型

如上所述,編譯器和處理器都可以以需要使用存儲器屏障的方式優化指令的執行。 影響編譯器和處理器的存儲器屏障是硬件存儲器屏障,並且僅影響編譯器的存儲器屏障是軟件存儲器屏障。

除硬件和軟件內存屏障外,內存屏障可以限制為內存讀取,內存寫入或兩者兼而有之。 影響讀取和寫入的內存屏障是完整的內存屏障。

還有一類特定於多處理器環境的內存屏障。 這些內存屏障的名稱以“smp”為前綴。 在多處理器系統上,這些障礙是硬件內存障礙,而在單處理器系統上,它們是軟件內存障礙。

barrier()宏是唯一的軟件內存屏障,它是一個完整的內存屏障。 Linux內核中的所有其他內存障礙都是硬件障礙。 硬件內存屏障是隱含的軟件障礙。

SW屏障有用的示例:請考慮以下代碼 -

for (i = 0; i < N; ++i) {
    a[i]++;
}

這個簡單的循環,使用優化編譯,很可能會展開和矢量化。 這里是匯編代碼gcc 4.8.0 -O3生成的打包(vector)操作:

400420:       66 0f 6f 00             movdqa (%rax),%xmm0
400424:       48 83 c0 10             add    $0x10,%rax
400428:       66 0f fe c1             paddd  %xmm1,%xmm0
40042c:       66 0f 7f 40 f0          movdqa %xmm0,0xfffffffffffffff0(%rax)
400431:       48 39 d0                cmp    %rdx,%rax
400434:       75 ea                   jne    400420 <main+0x30>

但是,在每次迭代時添加內聯匯編時,不允許gcc更改通過屏障的操作順序,因此它不能對它們進行分組,並且程序集將成為循環的標量版本:

400418:       83 00 01                addl   $0x1,(%rax)
40041b:       48 83 c0 04             add    $0x4,%rax
40041f:       48 39 d0                cmp    %rdx,%rax
400422:       75 f4                   jne    400418 <main+0x28>

但是,當CPU執行此代碼時,只要它不破壞內存排序模型,就允許對“引擎蓋下”的操作進行重新排序。 這意味着執行操作可以不按順序進行(如果CPU支持這種操作,那么這些日子大多數都是這樣做的)。 HW圍欄會阻止它。

評論僅限SW的障礙的有用性:

在某些微控制器和其他嵌入式平台上,您可能具有多任務處理,但沒有緩存系統或緩存延遲,因此沒有硬件屏障指令。 所以你需要做SW旋轉鎖之類的事情。 SW屏障可防止這些算法中的編譯器優化(讀/寫組合和重新排序)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM