2016-01-23 23 views
5

我有一個RingBuffer哪些服務一個消費者和一個生產者和使用兩個整數檢測新的數據:單生產者,單消費者環緩衝區的最小限制內存排序?

_lastReadIndex 
_lastWrittenIndex 

所以在ringbuffer未讀數據時,這兩個值不相等。

生產者增量(並且模緩衝緩衝區大小以環繞)_lastWrittenIndex當項目被添加到環緩衝區時。

消費者旋轉時,閱讀兩個值,檢查新數據,並在那裏,它會增量(和模量)_lastReadIndex

這三個突出的術語強調了關於多線程和內存障礙的要求。

我可以放寬這種設計的內存排序,佔據英特爾內存模型的多少?我相信英特爾的內存模型允許將更早的商店重新訂購到不同的地址。

編輯使用C++ 11原子庫std::memory_order_xxxx

+0

那麼,你想要爲C++ 11原子,或依賴於架構的決定(使用匯編)爲英特爾?在第一種情況下架構不相關,第二種情況下「C++」標籤無關。 – Tsyvarev

+0

對不起,C++ 11庫 – user997112

+0

問題是你在環形緩衝區中的索引取決於讀取_lastReadIndex值和**模數。所以這是兩個單獨的行爲。如果僅僅是讀取'_lastReadIndex'中的值,那麼讀取''獲取'和寫入'釋放'就足夠了。 – ViNi89

回答

1

你還有什麼之前做幾件事情:

模讀寫點,但保持_lastReadIndex_lastWrittenIndex完好知道如何你可用的許多數據,丟失了多少數據,或者如果超過完整週期後超過讀者,可能會阻止作者。

而且,非常重要的是,儘可能避免共享 - 將讀寫器變量放在單獨的緩存行上。現在

,你的問題:

如果你想成爲便攜,內存排序你需要在你的代碼不應該考慮的架構。標準的原子函數可以處理這個問題。 在增加寫入索引之前,您只需確保緩衝區中的數據可用,這意味着增量上的發佈語義。 您還必須確保寫入器將數據寫入內存,而不是優化爲僅保留在寄存器中。

newIndex = _lastWrittenIndex+1; 
buffer[newIndex % bufSize] = newData; 
atomic_store(&_lastWrittenIndex, newIndex, memory_order_release); 

在x86/64,這將是一樣的:

newIndex = _lastWrittenIndex+1; 
buffer[newIndex % bufSize] = newData; 
// release semantics means reorder barrier before action: 
barrier(); // translates to `asm volatile("":::"memory");` 
*(volatile int*)_lastWrittenIndex = newIndex; 

當編寫訪問代碼_lastWrittenIndex不超過絕對必要的,像上面,你可能也宣佈它的揮發性,但保持考慮到障礙仍然需要!

+0

值得指出的是,當消費者讀取_lastWrittenIndex時,它必須使用帶有memory_order_acquire的atomic_load。此外,_lastReadIndex需要類似的處理,因爲實際上消費者正在向生產者傳送空插槽。 –

相關問題