linux內存屏蔽技術

__asm__ __volatile__("": : :"memory");

內存屏障(memory barrier) 
#define set_mb(var, value) do { var = value; mb(); } while (0) 
#define mb() __asm__ __volatile__ ("" : : : "memory") 

1)set_mb(),mb(),barrier()函數追蹤到底,就是__asm__ __volatile__("":::"memory"),而這行代碼就是內存屏障。 
2)__asm__用於指示編譯器在此插入彙編語句 
3)__volatile__用於告訴編譯器,嚴禁將此處的彙編語句與其它的語句重組合優化。即:原原本本按原來的樣子處理這這裏的彙編。 
4) memory強制gcc編譯器假設RAM所有內存單元均被彙編指令修改,這樣cpu中的registers和cache中已緩存的內存單元中的數據將作 廢。cpu將不得不在需要的時候重新讀取內存中的數據。這就阻止了cpu又將registers,cache中的數據用於去優化指令,而避免去訪問內存。 
5)"":::表示這是個空指令。barrier()不用在此插入一條串行化彙編指令。在後文將討論什麼叫串行化指令。 
6)__asm__,__volatile__,memory在前面已經解釋
在linux/include/asm-i386/system.h定義:
#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
7)lock前綴表示將後面這句彙編語句:"addl $0,0(%%esp)"作爲cpu的一個內存屏障。
8)addl $0,0(%%esp)表示將數值0加到esp寄存器中,而該寄存器指向棧頂的內存單元。加上一個0,esp寄存器的數值依然不變。即這是一條無用的彙編 指令。在此利用這條無價值的彙編指令來配合lock指令,在__asm__,__volatile__,memory的作用下,用作cpu的內存屏障。
9)set_task_state()帶有一個memory barrier,set_task_state()肯定是安全的,但 __set_task_state()可能會快些。
關於barrier()宏實際上也是優化屏障:
#define barrier() __asm__ __volatile__("": : :"memory")
CPU越過內存屏障後,將刷新自己對存儲器的緩衝狀態。這條語句實際上不生成任何代碼,但可使gcc在barrier()之後刷新寄存器對變量的分配。     
             例1:
                1        int a = 5, b = 6;
                2        barrier();
                3        a = b;
      
            在line 3,GCC不會用存放b的寄存器給a賦值,而是重新讀內存中的b值,賦值給a。
           
           
例2:
它在進程上下文中將一個元素插入一個單向鏈表:
new->next=i->next;
wmb();
i->next=new;
同時,如果不加鎖地遍歷這個單向鏈表。或者在遍歷鏈表時已經可以看到new,或者new還不在該鏈表中。兩個內存寫
事件的順序必須按照程序順序進行。否則可能new的next指針將指向一個無效地址,就很可能出現 OOPS!

不論是gcc編譯器的優化還是處理器本身採用的大量優化,如Write buffer, Lock-up free, Non- blocking reading, Register allocation, Dynamic scheduling, Multiple issues 等,都可能使得實際執行可能違反程序順序,因此,引入內存屏障來保證事件的執行次序嚴格按程序順序來執行。

使用內存屏障強加的嚴格的CPU內存事件次序,保證程序的執行看上去象是遵循順序一致性模型。在當前的實現 中,wmb() 實際上是一個空操作,這是因爲目前Intel的CPU系列都遵循“處理機一致性”,所有的寫操作是遵循程序順序的,不會越過前面的讀寫操作。但是,由於 Intel CPU系列可能會在將來採用更弱的內存一致性模型並且其他體系結構可能採用其他放鬆的一致性模型,仍然在內核裏必須適當地插入wmb()保證內存事件的正 確次序。

內存屏障出現因爲編譯器或現在的處理器常會自作聰明地對指令序列進行一些處理,比如數據緩存,讀寫指令亂序執 行等等。如果優化對象是普通內存,那麼一般會提升性能而且不會產生邏輯錯誤。但如果對 I/O操作進行類似優化很可能造成致命錯誤。所以要使用內存屏障,以強制該語句前後的指令以正確的次序完成。其實在指令序列中放一個wmb的效果是使得指 令執行到該處時,把所有緩存的數據寫到該寫的地方,同時使得wmb前面的寫指令一定會在wmb的寫指令之前執行。


轉帖:http://blog.csdn.net/ssr3160183/article/details/6741700

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章