[英]Atomic access to shared memory
我在多個進程之間有一個共享內存,它以某種方式對內存進行交互。 前任:
DataBlock {
int counter;
double value1;
double ... }
我想要的是讓計數器自動更新/遞增。 並在該地址上發生內存釋放。 例如,如果我沒有使用共享內存,它將類似於
std::atomic<int> counter;
atomic_store(counter, newvalue, std::memory_order_release); // perform release operation on the affected memory location making the write visible to other threads
我如何為隨機內存位置實現這一點(解釋為上面的 DataBlock 計數器)? 我可以保證地址按照架構(x86 Linux)的要求對齊。
atomicupdate(addr, newvalue)
)memorysync(addr)
) - 我能看到的唯一方法是使用std::atomic_thread_fence(std::memory_order_release)
- 但這將“建立所有原子和寬松原子存儲的內存同步排序” - 就是這樣對我來說有點矯枉過正——我只想同步計數器位置。 欣賞任何想法。我不能在這里權威地回答,但我可以提供可能有幫助的相關信息。
互斥鎖可以在共享內存中創建和/或創建為跨進程。 Pthread 有一個特殊的創建標志,我不記得它是否使用共享內存,或者你共享一個句柄。 linux“futex”可以直接使用共享內存(注意用戶地址可能不同,但底層真實地址應該相同)
硬件原子在內存而不是進程變量上工作。 也就是說,您的芯片不會關心哪些程序正在修改變量,因此最低級別的原子自然會是跨進程的。 這同樣適用於柵欄。
C++11 未能指定跨進程原子。 但是,如果它們是無鎖的(檢查標志),則很難看出編譯器如何實現它們以使跨進程無法工作。 但是您會非常信任您的工具鏈和最終平台。
CPU 依賴性保證還跟蹤實際內存地址,因此只要您的程序在線程形式中是正確的,它在其多進程形式中也應該是正確的(關於可見性)。
Kerrek 是正確的,抽象機並沒有真正提到多個進程。 但是,它的同步細節以這樣一種方式編寫,即它們同樣適用於進程間,就像它們適用於多線程一樣。 這與 #3 有關:編譯器很難搞砸。
簡短的回答,沒有符合標准的方法來做到這一點。 但是,根據標准定義多線程的方式,您可以為高質量的編譯器做出很多假設。
最大的問題是是否可以簡單地在共享內存中分配原子(放置新)並工作。 顯然,這只有在它是真正的硬件原子時才有效。 然而,我的猜測是,使用高質量的編譯器/庫,C++ 原子應該可以在共享內存中找到。
玩得開心驗證行為。 :)
由於您在 Linux 上,因此您可以在counter
的地址上使用gcc
atomic 內置__sync_fetch_and_add()
...根據atomic built-ins 上的 gcc-documentation ,這也將實現完整的內存圍欄,而不是釋放操作,但是由於您實際上想要讀取-修改-寫入操作而不是簡單的加載(即,遞增計數器不僅僅是加載,但您必須讀取,然后修改,最后寫回值),全內存圍欄將是執行此操作的正確內存順序的更好選擇。
我正在查看標准草案 N4820 [atomics.lockfree],它說:
4 [注意:無鎖的操作也應該是無地址的。 也就是說,通過兩個不同地址對同一內存位置的原子操作將以原子方式進行通信。 實現不應依賴於任何每個進程的狀態。 此限制允許通過多次映射到一個進程的內存和兩個進程之間共享的內存進行通信。 ——尾注]
因此,如果您的目標是無地址,則先決條件是無鎖的,這可以通過 std::atomic 進行檢查。
但是,我不確定如何創建atomic
對象。 將對象放在共享內存中是否足夠好? 我還沒有找到任何關於這種用法的規范,而我確實在 github 上看到了這樣的代碼用法。
(編者注:您將指針投射到共享內存,例如auto p = static_cast<atomic<int>*>(ptr);
與訪問任何其他類型的共享內存相同。)
您可以使用鎖定和等待機制來遞增計數器。 Boost Library提供了一種鎖定和等待機制。 查看此鏈接以供參考
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.