[英]Do I need an atomic type in shared memory in this particular case?
我有多個進程使用boost共享內存。 編寫器進程將寫入共享內存中的數組,如下所示:
void push(int32_t val_)
{
int nextIndex = _currentIndex.fetch_add(1,std::memory_order_relaxed);
_buffer[nextIndex] = val_;
}
//val_ is guaranteed to be >=1
//_buffer is an array of int32_t in shared memory initialized to 0
單個讀者進程將如下所示:
void process()
{
int idx=0;
while(running)
{
int32_t val = _buffer[idx];
if(val)
{
//do some work...
++idx;
}
}
}
根據提升:“地址范圍的變化會自動被其他進程看到,這些進程也映射了相同的共享內存對象。”
我的問題是,假設_buffer正確對齊,_buffer可以只是一個int32_t數組,還是絕對有必要將_buffer定義為std :: atomic數組? 寫入int32_t在x86上是原子的,假設對齊是正確的,並且boost保證其他進程將看到更新。
CPU信息:
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 24
On-line CPU(s) list: 0-23
Thread(s) per core: 1
Core(s) per socket: 12
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel
CPU family: 6
Model: 63
Stepping: 2
CPU MHz: 2596.945
BogoMIPS: 5193.42
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 30720K
NUMA node0 CPU(s): 0-5,12-17
NUMA node1 CPU(s): 6-11,18-23
正如你自己寫的那樣,一個線程寫入一些內存位置:
_buffer[nextIndex] = val_;
另一個線程讀取內存位置:
int32_t val = _buffer[idx];
根據標准,該內存地址必須同步,否則它是未定義的行為。
該數組必須是原子數組,由互斥鎖或快速自旋鎖保護的簡單數組或其讀寫同步的任何其他數組。
TL; DR :即使這樣,您也需要同步訪問。 並使用原子,而不是普通的互斥體。
這里有一些問題:
首先,您有一個編寫器線程和一個讀取器線程,寫入和讀取相同的內存位置。 這意味着必須保護對該位置的訪問(使用鎖,原子操作,圍欄等)。這些線程在不同進程中的事實不會進入它。 您仍然需要解決數據爭用問題。
其次,盡管Boost文檔說其他映射該區域的進程會自動看到更改,但我認為這只是一種簡化。 共享內存庫不能為不同進程之間的共享內存提供比同一進程中不同線程存在的更強的保證。 所有相同的問題仍可能出現:您的讀/寫可能由編譯器或CPU甚至內存系統重新排序,甚至完全省略或與其他讀/寫組合。 並且需要考慮緩存和MMU效果。
因此,即使您的數據已正確對齊,並且對該數據類型的寫入在您的體系結構中是原子的,但如果您不保護訪問,則它不會對數據爭用導致的錯誤行為提供任何安全性。 這里沒有魔力; 如果在有線程時必須同步/保護/原子化訪問,則還需要對進程執行相同操作。 你可能還需要做更多。
第三,適用於同一進程內的線程的同步原語可能(並且可能不會)跨不同進程工作。 原子操作(或類型,如C ++已實現它們)確實有效。 內存柵欄可能也可以工作,具體取決於您正在做什么。 但是,IIRC,Boost的共享內存庫提供了跨進程邊界工作的特殊同步原語(如果放在共享區域內)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.