記憶體屏障 barrier 與mb

2021-05-27 04:51:37 字數 1479 閱讀 5880

barrier() 靜態記憶體屏障,防止編譯階段的亂序與優化。

mb() 動態記憶體屏障,防止cpu處理的亂序。

barrier()在x86中的實現就是一行內嵌彙編**:

__asm volatile("": : :"memory");
告訴編譯器,barrier()前後的記憶體操作要確保按順序實實在在的進行。

測試**如下:

int ga = 0;

int gb = 0;

#define barrier() __asm__ volatile("":::"memory")

int foo(int i)

對應彙編**分別為:

#沒有barrier()

foo:

pushl %ebp

movl %esp, %ebp

movl 8(%ebp), %eax

popl %ebp

movl %eax, %edx

imull %eax, %edx

movl %eax, gb

movl %edx, ga

leal (%edx,%eax), %eax

ret#加入barrier()

foo:

pushl %ebp

movl %esp, %ebp

movl 8(%ebp), %eax

movl %eax, %edx

imull %eax, %edx

movl %edx, ga

movl %eax, gb

popl %ebp

addl ga, %eax

ret

分析結論:

1. 沒有barrier()時,ga與gb的賦值順序與c**相反;

加入barrier()後,ga與gb的賦值順序與c**相同。

2. 沒有barrier()時,return的值是直接通過暫存器計算出來的;

加入barrier()後,return時,ga的值需要重新從記憶體中讀取。

雖然barrier()從彙編**角度保證了ga與gb的賦值順序,但是在支援亂序處理的cpu上,還是有可能打亂其順序,因為cpu並不知道其依賴關係。這時,就需要使用mb()來保障順序。

另一方面,使用barries()後[movl    %edx, ga]和[addl    ga, %eax]兩條語句有明確的資料依賴關係,所以cpu絕不會打亂順序執行。

綜上述:

1. barries() 能保證同一記憶體位址的讀寫操作按序實實在在的進行,會重新整理暫存器的快取。

典型情況:[a++; barries(); b=a;]一定會讀兩次記憶體,而[a++; b=a;]則只會讀一次。

2. 要是兩個不同記憶體操作的保序就得需要mb()來作保障。

QNX多執行緒同步之Barrier 屏障

之前和大家介紹過qnx上的執行緒同步方法metux和semophore,通過這兩種方法可以對乙個或者幾個資源進行加鎖,避免資源使用上的衝突。在另一種情況下,某個執行緒需要在其它執行緒完成工作後才繼續執行,這時就需要使用到執行緒同步方法barrier。舉個現實的例子,假設有三個士兵在操作一門高炮,乙個...

QNX多執行緒同步之Barrier 屏障

之前和大家介紹過qnx上的執行緒同步方法metux和semophore,通過這兩種方法可以對乙個或者幾個資源進行加鎖,避免資源使用上的衝突。在另一種情況下,某個執行緒需要在其它執行緒完成工作後才繼續執行,這時就需要使用到執行緒同步方法barrier。舉個現實的例子,假設有三個士兵在操作一門高炮,乙個...

QNX多執行緒同步之Barrier 屏障

之前和大家介紹過qnx上的執行緒同步方法metux和semophore,通過這兩種方法可以對乙個或者幾個資源進行加鎖,避免資源使用上的衝突。在另一種情況下,某個執行緒需要在其它執行緒完成工作後才繼續執行,這時就需要使用到執行緒同步方法barrier。舉個現實的例子,假設有三個士兵在操作一門高炮,乙個...