Ada 程式設計/編譯指示/Atomic
pragma Atomic (local_name);
Atomic 是一個 表示編譯指示,它可以與型別和變數一起使用,以指定生成的程式碼必須以原子方式從記憶體中讀取和寫入型別或變數,即作為單個/不可中斷的操作。它隱含了編譯指示 Volatile,不同之處在於編譯指示 Atomic 更強大:如果無法以原子方式更新變數,則編譯必須失敗。
這通常用於與硬體暫存器互動的上下文中,這些暫存器必須以原子方式寫入,並且編譯器不得重新排序或抑制任何冗餘讀寫操作。在某些情況下,它也可以用於任務,但對於 Ada 任務的通訊,使用保護型別 或其他同步原語更安全。
Device_Status : Status_Register;pragmaAtomic (Device_Status);forDevice_Status'Addressuse[[Ada Programming/Libraries/|]].System.Storage_Elements.To_Address (16#8010_FF74#);
幾乎總是錯誤地將 atomic 或 volatile 變數用於 任務.[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
如您所見,不會生成原子增量指令或 test-and-set 操作碼。與其他程式語言一樣,如果程式中需要這些特定指令,則必須使用機器程式碼插入顯式地寫入它們。[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] 因此,在將原子物件用於任務資料共享或同步時,尤其是在多處理器中,應格外小心。
- ↑ Arch Robison (2007-11-30). "Volatile: Almost Useless for Multi-Threaded Programming". Intel Software Network. Retrieved 2008-05-30.
There is a widespread notion that the keyword volatile is good for multi-threaded programming (...) volatile is almost useless for multi-threaded programming.
- ↑ a b Ian Lance Taylor (2008-03-05). "Volatile". Retrieved 2008-05-28.
Using [the C/C++ qualifier] volatile does not mean that the variable is accessed atomically; no locks are used. Using volatile does not mean that other cores in a multi-core system will see the memory accesses; no cache flushes are used. (...) Using volatile does not imply any sort of memory barrier; the processor can and will rearrange volatile memory accesses. (...) You should not use more than one such variable to communicate between any pair of threads, as there is no guarantee that the different threads will see the accesses in the same order.
- ↑ Laurent Guerby (1995). "C.5 Shared Variable Control". Ada 95 Rationale. Intermetrics.
A need to access specific machine instructions arises sometimes (...). Examples include instructions that perform compound operations atomically on shared memory, such as test-and-set and compare-and-swap (...)
{{cite book}}:|access-date=requires|url=(help); External link in(help); Unknown parameter|chapter=|month=ignored (help) - ↑ Sarita V. Adve, Kourosh Gharachorloo (1996). "Shared Memory Consistency Models: A Tutorial" (PDF). IEEE Computer. 29 (12): 66–76. Retrieved 2008-05-28.
{{cite journal}}: Unknown parameter|month=ignored (help)
Atomic 是 Ada 95 以來標準的編譯指示,定義在系統程式設計附錄(附錄 C)中。這是一個專門需求的附錄,因此該編譯指示在那些沒有實現該附錄的編譯器中不可用。
Atomic 是不同平臺之間可移植性的輔助工具。例如,在 64 位架構與 32 位架構之間移植時,編譯器將藉助此 pragma 檢測可移植性問題。
pragma Atomic 的效果可以在 C 中使用以下型別實現volatile sig_atomic_t,在 signal.h 中定義(在 C++ 中稱為volatile std::sig_atomic_t)。值得注意的是,可以可移植地儲存在此型別中的唯一值是 0–127,[2] 而 Ada pragma 並沒有施加任何特定的限制(除了原子物件的型別)。
但是,這種 C 型別很少為程式設計師所知。因此,C 中的volatile限定符被廣泛用於易變資料和原子資料,即使需要原子訪問。因此,在與現有 C 程式碼進行介面時,程式設計師必須首先閱讀程式碼以瞭解資料是否需要原子載入和儲存。如果需要,應在 Ada 端使用 pragma Atomic 或 Atomic_Components 標記資料。否則,應改為新增 pragma Volatile 或 Volatile_Components。
C++11 和 C11 包含了原子操作和型別,[3] 但與 Ada 中的語義不同,也不相容。
- Ada 程式設計
- Ada 程式設計/Pragmas
- Ada 程式設計/Pragmas/Volatile
- Ada 程式設計/Pragmas/Atomic Components
- Ada 程式設計/Pragmas/Volatile Components
- Ada 程式設計/Pragmas/Shared(已過時)
- ↑ Robert Dewar (1996-02-17)。“pragma Shared (was Ada is almost ....)”。comp.lang.ada。 (網路連結)。於 2008-05-28 檢索。 “pragma Atomic 與 pragma Volatile 完全不同。 Ada 中的 pragma Atomic 本質上等同於 Ada 83 中的 pragma Shared。Ada 中的 pragma Volatile 本質上等同於 C 中的 volatile,並且是 Ada 83 中沒有的功能。”
- ↑ Justin Pincar (2008-11-19)。“DCL34-C. 對無法快取的資料使用 volatile”。CERT C 安全編碼標準。 計算機緊急響應小組. 於 2009-01-10 檢索。
從 0 到 127 的整數值可以安全地儲存到型別為 sig_atomic_t 的變數中。
- ↑ Herb Sutter (2009-01-08)。“volatile vs. volatile”。Dr. Dobb's. 於 2009-01-10 檢索。
ISO C++ 在 2007 年將它們新增到 C++0x 草案標準中,使用模板名稱 atomic<T>(例如,atomic)。它們從 2008 年開始在 Boost 專案 和其他實現中變得可用。ISO C++ 原子庫還提供了一種與 C 相容的方式來拼寫這些型別及其操作(例如,atomic_int),這些型別似乎很可能在將來被 ISO C 採用。
{{cite journal}}: 外部連結在(幫助)|quote=
