繁体   English   中英

在这种特殊情况下,我是否需要共享内存中的原子类型?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM