我有一个RingBuffer可以为一个使用者和一个生产者提供服务,并使用两个整数来检测新数据:
_lastReadIndex
_lastWrittenIndex
因此,当这两个值不相等时,环形缓冲区中有未读数据。
将项目添加到环形缓冲区时,生产者会递增(以及模数随环形缓冲区的大小而变化)_lastWrittenIndex
。
消费者旋转,读取两个值,检查是否有新数据,如果有,它将增加(和模数)_lastReadIndex
。
突出显示的三个术语强调了有关多线程和内存屏障的要求。
考虑到英特尔的内存模型,我可以在多大程度上放宽此设计的内存顺序?我相信英特尔的内存模型允许将早期存储中的负载重新排序到其他地址吗?
使用C ++ 11原子库std::memory_order_xxxx
等进行编辑
您必须先完成几件事:
模读写点,但保持_lastReadIndex
和_lastWrittenIndex
完整知道你有多少数据可用,多少丢失,或者作家mayhaps块,如果超支完整的周期后的读者。
而且,非常重要的是,避免尽可能多地共享-将读取器和写入器变量放在单独的缓存行中。
现在,对您的问题:
如果您想变得可移植,则代码中所需的内存顺序不应考虑该体系结构。标准的原子功能可以解决这个问题。在增加写索引之前,您只需要确保缓冲区中的数据可用即可,这意味着在该增量上释放语义。您还必须确保写入器将数据写入内存,并且不进行优化以仅保留在寄存器中。
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
像上面那样,编写的代码访问的绝对访问权限绝对不是绝对必要的时,您最好声明它是易失的,但要记住仍然需要障碍!
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句