2017-04-22 73 views
3

爲了讓事情變得簡單並且爲了專注於我的問題的核心,讓我們假設由指針變量ptr在本地尋址的內存位置在幾個進程之間共享。我特別使用C/++中的MPI共享內存窗口來分配和共享內存。要具體,讓我們說ptr引用一個浮點變量,所以在當地我們有特定共享內存寫入操作(MPI)的同步

float* ptr; 

現在假設所有進程嘗試寫入相同的值const float f到PTR,即

*ptr = f; 

我的問題是:考慮到所有進程試圖以相同的方式修改字節的事實,即該事件f對於每個進程具有相同的值,這個操作是否需要同步或者是否可以同時執行。因此,我的問題歸結爲:對於並行寫入操作浮點變量,是否有競爭條件導致不一致的字節模式的可能性,雖然每個進程都嘗試以相同的方式修改內存。即如果我確實知道每個進程都寫入相同的數據,那麼我可以省略同步嗎?

回答

1

是的,您必須同步共享內存。修改線程駐留在不同進程中的事實沒有任何意義,它仍然是數據競爭(從不同線程寫入共享內存)。

請注意同步對象解決的其他問題,如可見性和內存重新排序,寫入共享內存的內容是不相關的。

目前,該標準沒有定義進程的思想(僅限於線程),也沒有提供任何方法輕鬆實現進程之間的同步。

您在共享內存中分配一個std::mutex,並將其用作同步原語,或者使用它作爲同步原語,或者依賴於互斥,信號量或事件等win32進程間同步原語。或者,如果您只想同步基元,則可以在共享內存上分配一個std::atomic<T>,並將其用作同步原語。

+0

非常感謝您的回答。你能否更詳細地說出你的意思是「在不同的流程中調整大小沒有意義」?如果我在MPI中實現了正確的同步(這肯定我知道該怎麼做),我甚至不會使用同步對象。所以我不明白「能見度,記憶重排」因素如何?我肯定不會使用任何C++標準庫功能來解決這個問題。另請注意,衝突在訪問數據的不同進程之間,而不是線程之間。 – sperber

+0

這是一個錯字,它是「居住」。如果您的MPI提供同步,這是一個不同的問題,我根據您的示例進行了回答,例如,寫入來自不同進程的裸指針 –

+0

因此,在使用多個進程寫入相同數據的內存重新排序方面會出現什麼問題,即組件級別會出現什麼問題? – sperber

1

在C++中,如果多個進程在沒有正確使用同步原語或原子操作的情況下寫入相同的內存位置,則會發生未定義的行爲。 (也就是說,它可能工作,它可能無法正常工作,電腦可能着火。)

實際上,在您的計算機上,基本上可以按照您認爲它應該工作的方式工作。實際上,在某些體系結構中,事情並不如預期的那樣順利:如果CPU無法讀取/寫入與共享值一樣小的內存塊,或共享值的存儲跨越對齊邊界,這樣的寫入實際上也可以涉及讀取,而讀取 - 修改 - 寫入可以具有恢復或破壞對存儲器的其他改變的效果。

得到你想要的東西,最簡單的方法就是做寫爲「寬鬆」的原子操作:

std::atomic_store_explicit(ptr, f, std::memory_order_relaxed); 

這確保了寫爲「原子」在不造成一個數據的意義除了在*ptr = f可能存在潛在問題的架構之外,不會發生任何開銷。

+0

優秀的答案,謝謝,這些都是我正在尋找/懷疑的細節和提示。 – sperber

+0

請注意,這是「memory_order_relaxed」實際上是個好主意的情況之一。一般來說,對共享內存的所有訪問都應該使用同步原語來保護,或者使用更強的內存排序來完成。 – Sneftel