跳轉到內容

Ada 程式設計/編譯指示/Volatile

來自華夏公益教科書,開放的書籍,用於開放的世界

Ada. Time-tested, safe and secure.
Ada. 經久耐用,安全可靠。
pragma Volatile (local_name);

Volatile 是一種 表示編譯指示,可用於型別和變數,以指定所討論的變數的值可能會突然發生變化。例如,這可能是由於裝置寫入共享緩衝區造成的。

當使用此編譯指示時,編譯器必須抑制任何會干擾對易失性變數的正確讀取的最佳化。例如,對同一變數的兩次連續讀取不能最佳化為僅一次讀取,也不能重新排序。

與編譯指示 AtomicAtomic_ComponentsVolatile_Components 進行比較。

type Video_Buffer is array (Natural range <>) of RGB_Value;
pragma Volatile (Video_Buffer);

錯誤用法

[編輯 | 編輯原始碼]

對於 任務 來說,使用 atomicvolatile 變數幾乎總是錯誤的。[1] 當一個物件是原子性的時,它僅僅意味著它將被原子地從記憶體中讀取或寫入。編譯器不會在訪問該物件時生成原子指令或記憶體屏障,它只會

  • 檢查體系結構是否保證原子記憶體載入和儲存,
  • 禁止某些編譯器最佳化,例如重新排序或抑制對物件的冗餘訪問。

例如,以下程式碼,其中A是一個原子物件,可能會被誤解

A := A + 1;  -- Not an atomic increment!

編譯器不會(並且根據標準也不允許)生成原子增量指令來直接增量並從記憶體中更新變數A.[2] 這是編譯器生成的程式碼

  A := A + 1;
804969f:	a1 04 95 05 08       	mov    0x8059504,%eax
80496a4:	40                   	inc    %eax
80496a5:	a3 04 95 05 08       	mov    %eax,0x8059504

可以看出,不會生成原子增量指令或測試和設定操作碼。與其他程式語言一樣,如果程式中需要這些特定指令,則必須使用機器碼插入顯式編寫。[3]

上面的程式碼片段等效於以下程式碼(這兩個程式碼序列生成完全相同的目的碼),其中T是一個(非原子)臨時變數

T := A;      -- A is copied atomically to local variable T
T := T + 1;  -- local variable T is incremented
A := T;      -- A is stored atomically

因此,從多個任務同時修改原子變數是不正確的。例如,兩個任務並行增量計數器。即使在單處理器上,也應該使用其他 Ada 任務功能,例如受保護物件。在多處理器上,根據 記憶體一致性模型,使用各種原子或易失性變數進行任務通訊可能會產生意想不到的結果。[2][4] 因此,在使用原子物件進行任務資料共享或同步時,尤其是在多處理器中,應格外小心。

  1. Arch Robison (2007-11-30). "Volatile: Almost Useless for Multi-Threaded Programming". Intel 軟體網路. 檢索於 2008-05-30. 有一種普遍的觀點認為,關鍵字 volatile 對多執行緒程式設計很有用 (...) volatile 對多執行緒程式設計幾乎沒有用處。
  2. a b Ian Lance Taylor (2008-03-05). "Volatile". 檢索於 2008-05-28. 使用 [C/C++ 限定符] volatile 並不意味著變數是以原子方式訪問的;不使用鎖。使用 volatile 並不意味著多核系統中的其他核心將看到記憶體訪問;不使用快取重新整理。(...) 使用 volatile 並不意味著任何形式的記憶體屏障;處理器可以並且將會重新排列 volatile 記憶體訪問。(...) 您不應該使用多個這樣的變數在任何一對執行緒之間進行通訊,因為無法保證不同的執行緒會以相同的順序看到訪問。
  3. Laurent Guerby (1995). "C.5 Shared Variable Control". Ada 95 論證. Intermetrics. 有時需要訪問特定的機器指令 (...). 例如,在共享記憶體上執行復合操作的原子指令,例如測試和設定和比較和交換 (...) {{cite book}}: |access-date= requires |url= (幫助); External link in |chapter= (幫助); Unknown parameter |month= ignored (幫助)
  4. Sarita V. Adve, Kourosh Gharachorloo (1996). "Shared Memory Consistency Models: A Tutorial" (PDF). IEEE Computer. 29 (12): 66–76. 檢索於 2008-05-28. {{cite journal}}: Unknown parameter |month= ignored (幫助)

可移植性

[編輯 | 編輯原始碼]

Ada 版本

[編輯 | 編輯原始碼]
  • 此編譯指示在 Ada 95 和 Ada 2005 中可用(附件 C,一個專門需求附件)。
  • 在 Ada 83 中,沒有一個完全等同於 Volatile 的標準編譯指示。但是,編譯指示 Shared 與 Atomic 相似(儘管它自 Ada 95 以來已過時),[1] 並且一些編譯器為此目的添加了一個實現定義的編譯指示。[2]

編譯器

[編輯 | 編輯原始碼]

Volatile 自 Ada 95 以來就是一個標準編譯指示,定義在系統程式設計附件(附件 C)中。這是一個專門需求附件,因此此編譯指示在那些沒有實現該附件的編譯器中不可用。

此編譯指示可移植到不同的架構和作業系統。

在 C/C++ 中,volatile限定符等效於此編譯指示。但是,此 C 限定符用於易變和原子資料,即使需要原子訪問也是如此。因此,在與現有 C 程式碼進行介面時,程式設計師必須閱讀程式碼以瞭解資料是否需要原子載入和儲存。如果需要,資料應在 Ada 側使用編譯指示 AtomicAtomic_Components 標記,否則使用編譯指示 Volatile 或 Volatile_Components

編碼規則

[編輯 | 編輯原始碼]

沒有地址子句的易變物件

[編輯 | 編輯原始碼]

在許多情況下,當易變物件用於與硬體裝置進行介面時,它也應該有一個地址子句。

  • gnatcheck
 +R Volatile_Objects_Without_Address_Clauses
  • AdaControl
 check object_declarations (volatile_no_address);

另請參閱

[編輯 | 編輯原始碼]

華夏公益教科書

[編輯 | 編輯原始碼]

Ada 參考手冊

[編輯 | 編輯原始碼]

Ada 95 理性

[編輯 | 編輯原始碼]

Ada 95 質量和風格指南

[編輯 | 編輯原始碼]
  1. 羅伯特·德沃(1996 年 2 月 17 日)。"編譯指示 Shared(是 Ada 幾乎是……)". comp.lang.ada. (網頁連結). 檢索於 2008 年 5 月 28 日。 "編譯指示 Atomic 與編譯指示 Volatile 截然不同。 Ada 中的編譯指示 Atomic 本質上與 Ada 83 中的編譯指示 Shared 相同。 Ada 中的編譯指示 Volatile 本質上與 C 中的 volatile 相同,它是在 Ada 83 中不可用的功能。"
  2. "實現定義的編譯指示". GNAT Pro 參考手冊. 檢索於 2008 年 6 月 2 日. [編譯指示 Volatile] 在一些 Ada 83 編譯器中提供,包括 DEC Ada 83。 Ada 95 / Ada 2005 中編譯指示 Volatile 的實現與 DEC Ada 83 中的實現向上相容。 {{cite book}}: 未知引數 |chapterurl= 被忽略 (|chapter-url= 建議) (幫助)
華夏公益教科書