Can you summarize the following document?
        
  在C,以及C++中,volatile關鍵字的作用:  根據相關的標準(C,C++,POSIX,WIN32)和目前絕大多數實現,對volatile變數的操作並不是原子的,也不能用來為執行緒建立嚴格的happens-before關係。codice_3關鍵字就像行動式執行緒構建一樣基本沒什麼用處。  Visual C++ 2005 保證volatile變數是一種記憶體屏障,阻止編譯器和CPU重新安排讀入和寫出語義。 在先前版本的Visual C++則沒有此類保證。在其他方面將指標定義為volatile可能會影響程式的效能。例如,如果指標定義對程式碼的其他地方可見,強制編譯器將指標視為屏障,就會降低程式的效能,這是完全不必要的。

  基本型別的物件用volatile修飾後,仍舊支援所有的操作(加、乘、賦值等)。但是,使用者定義的非基本型別(class、struct、union)的物件被volatile修飾後,具有不同行為:

  臨界區內部,通過互斥鎖(mutex)保證只有一個執行緒可以訪問,因此臨界區內的變數不需要是volatile的;而在臨界區外部,被多個執行緒訪問的變數應為volatile,這也符合了volatile的原意:防止編譯器快取(cache)了被多個執行緒併發用到的變數。volatile物件只能呼叫volatile成員函式,這意味著應僅對多執行緒併發安全的成員函式加volatile修飾,這種volatile成員函式可自由用於多執行緒併發或者重入而不必使用臨界區;非volatile的成員函式意味著單執行緒環境,只應在臨界區內呼叫。在多執行緒程式設計中可以令該資料物件的所有成員函式均為普通的非volatile修飾,從而保證了僅在進入臨界區(即獲得了互斥鎖)後把該物件顯式轉為普通物件之後才能呼叫該資料物件的成員函式。這種用法避免了程式設計者的失誤——在臨界區以外訪問共享物件的內容: 對於內建型別,不應直接用volatile,而應把它包裝為結構的成員,就可以保護了volatile的結構物件不被不受控制地訪問。

  在這裡例子中,程式碼將codice_4的值設定為codice_5。然後開始不斷地輪詢它的值直到它變成codice_6:  一個執行優化的編譯器會提示沒有程式碼能修改codice_4的值,並假設它永遠都只會是codice_5.因此編譯器將用類似下列的無限迴圈替換函式體:  但是,foo可能指向一個隨時都能被計算機系統其他部分修改的地址,例如一個連線到中央處理器的裝置的硬體暫存器,上面的程式碼永遠檢測不到這樣的修改。如果不使用volatile關鍵字,編譯器將假設當前程式是系統中唯一能改變這個值部分(這是到目前為止最廣泛的一種情況)。 為了阻止編譯器像上面那樣優化程式碼,需要使用volatile關鍵字:  這樣修改以後迴圈條件就不會被優化掉,當值改變的時候系統將會檢測到。

  下面的C程式和後面的彙編程式碼展示了codice_3關鍵字如何影響編譯器的輸出。這裡使用的編譯器是GCC。

  Java也支援 codice_3 關鍵字,但它被用於其他不同的用途。當 codice_3 用於一個作用域時,Java保證如下: 使用codice_3會比使用鎖更快,但是在一些情況下它不能工作。codice_3使用範圍在Java5中得到了擴充套件,特別是雙重檢查鎖定現在能夠正確工作。

  在Ada中,比起關鍵字,codice_18標記更像是一種指令。“對於volatile物件而言,所有讀和更新都會作為一個整體直接執行到記憶體”。
在程式設計中,尤其是在C語言、C++、C#和Java語言中,使用volatile關鍵字宣告的變數或物件通常具有與優化、多執行緒相關的特殊屬性。通常,volatile關鍵字用來阻止(偽)編譯器認為的無法“被程式碼本身”改變的程式碼(變數/物件)進行優化。如在C語言中,volatile關鍵字可以用來提醒編譯器它後面所定義的變數隨時有可能改變,因此編譯後的程式每次需要儲存或讀取這個變數的時候,都會直接從變數地址中讀取資料。如果沒有volatile關鍵字,則編譯器可能優化讀取和儲存,可能暫時使用暫存器中的值,如果這個變數由別的程式更新了的話,將出現不一致的現象。