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。舉個現實的例子,假設有三個士兵在操作一門高炮,乙個...