2012-01-06 143 views
9

我有一個共享內存之間的多個進程以特定方式插入內存。 例如:原子訪問共享內存

DataBlock { 
int counter; 
double value1; 
double ... } 

我要的是計數器進行更新/原子遞增。並在該地址發生內存釋放。 如果我使用的werent共享內存,例如,它會像

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 

如何做到這一點的隨機存儲位置(解釋爲數據塊計數器>以上)。我可以保證該地址按照架構(x86 linux)的要求對齊

  1. 使更新原子化 - 如何? (即atomicupdate(addr,newvalue))
  2. 內存同步多核 - (即memorysync(addr)) - 我可以看到的唯一方法是使用std :: atomic_thread_fence(std :: memory_order_release) - 但這將「建立內存所有原子和放鬆的原子商店的同步排序「 - 這對我來說是過度的 - 我只想讓計數器位置同步。 欣賞任何想法。
+3

我只是猜測,但我的印象是,C++編程模型沒有「進程」的概念,內存模型沒有「共享內存」的概念,所以我懷疑標準本身會使任何保證。共享內存非常依賴於平臺功能,因此請查閱您的平臺文檔。 – 2012-01-06 14:59:51

+0

你可以在你的DataBlock中放入一個'atomic '嗎?只要'atomic '是無鎖的(標準顯式提及內存在進程間共享作爲這些用例的用例),這應該工作。不,你不能只是得到一個隨機地址原子(見http://stackoverflow.com/questions/8749038/how-to-use-stdatomic-efficiently/8749474)@Kerrek SB:實際上,這種情況被提及[atomics.lockfree]在最後的草稿中。 – Grizzly 2012-01-06 15:22:46

+0

@Grizzly:你的意思是非規範性說明29.4/3?非常有趣,我不知道。 – 2012-01-06 15:26:40

回答

-2

您可以使用鎖&等待機制,增加計數器。 Boost庫提供了一個鎖定和等待機制。檢查這個鏈接reference

9

我無法用這裏的權威回答,但我可以提供可能有幫助的相關信息。

  1. 互斥量可以在共享內存中創建和/或創建爲跨進程。 Pthread有一個特殊的創建標誌,我不記得是否使用共享內存,或者你共享一個句柄。 linux「futex」可以直接使用共享內存(注意用戶地址可能不同,但底層實際地址應該是相同的)

  2. 硬件原子工作在內存上而不是過程變量。也就是說,你的芯片不會關心哪些程序正在修改變量,因此最低級別的原子將會自然地跨進程。這同樣適用於圍欄。

  3. C++ 11無法指定跨進程原子。但是,如果它們是無鎖的(檢查標誌),很難看到編譯器如何實現它們,從而使跨進程無法工作。但是你會對你的工具鏈和最終平臺產生很大的信心。

  4. CPU依賴性保證還會跟蹤實際內存地址,因此只要您的程序在線程化形式下正確,它的多進程形式(關於可見性)也應該是正確的。

  5. Kerrek是正確的,抽象機器沒有提到多個進程。但是,它的同步細節的編寫方式使得它們同樣適用於跨進程,就像它們對多線程所做的一樣。這與#3有關:編譯器很難將其搞砸。

簡而言之,沒有符合標準的方法可以做到這一點。然而,依靠標準定義多線程的方式,可以爲質量編譯器做出很多假設。

最大的問題是一個原子是否可以簡單地分配到共享內存中(放置新的)並工作。顯然這隻有在它是一個真正的硬件原子時纔有效。然而,我的猜測是,對於高質量的編譯器/庫文件,C++原子應該在共享內存中工作。

玩得開心驗證行爲。 :)

4

既然你是在Linux上,你可以使用gcc原子內置__sync_fetch_and_add()上的地址爲counter ......根據gcc-documentation on atomic built-ins,這也將實行全方位的存儲柵欄,不釋放操作,但是由於你實際上需要一個讀 - 修改 - 寫操作而不是簡單的加載(例如,增加一個計數器不僅僅是一個負載,而且你必須讀取,然後修改並最終回寫該值)內存圍欄將成爲執行此操作的正確內存排序的更好選擇。

+0

'__sync_fetch_and_add()'可以使用,但我認爲'__sync_sub_and_fetch()'更合適。你減少引用計數,並釋放,如果它下降到零。它保證,如果兩個線程同時從2遞減,只有一個將返回0(並且將釋放)。 – ugoren 2012-01-06 20:30:02

+0

這絕對是一個很好的建議...一個原子內置將用於複製過程中的增量等,另一個用於在不再使用該引用時降低該值。 – Jason 2012-01-06 21:15:41