我对使用无锁队列有疑问。
假设我有一个单生产者单一消费者队列,其中 生产者和消费者必然会分开核心。队列元素 是共享内存的缓冲区,由生产者和 消费者一开始。
生产者获取队列元素,用数据填充缓冲区 将它排队,消费者将元素排队,读取它 以某种方式处理它。
作为无锁队列的用户,我是否必须明确确保这一点 生产者编写的缓冲区对用户可见吗?或者是 CAS(或其他类似的)原语在算法的核心自动提供 屏障?
我见过的几个例子使用整数作为有效载荷, 所以这个内存同步的问题不会出现。
谢谢,
答案 0 :(得分:0)
比较和交换等互锁原语通常具有不同的内存屏障语义。它们在架构之间有所不同,但通常你会想要(最迟)在生产者中使用“释放”语义,使结构对消费者可见,并且在你之前在消费者中使用“获取”语义访问数据结构。
在某些体系结构(特别是vanilla x86)上,您实际上并没有做出选择,因为每个互锁操作意味着一个完整的障碍 - 但如果这让您养成不要求任何障碍的习惯将,由于墨菲,回来咬你的其他建筑。
(相反,也是由于Murphy,如果你仔细研究选项并在各处插入正确的障碍,事件可能会合谋使得除了x86之外,你所编写的代码都不需要运行。)< / p>
答案 1 :(得分:0)
根据定义,这是特定于体系结构的。对于Intel CPU上的GCC,请使用GCC Atomic Builins - 其中大多数意味着完全内存屏障。
答案 2 :(得分:0)
一些建议将记忆障碍与CAS联系起来; x86 / x64是一个。
其他(例如ARM)没有。在ARM上,执行LL / SC,在之前和之后都使用手动数据内存屏障。
答案 3 :(得分:0)
作为无锁队列的用户,我是否必须明确确保生产者编写的缓冲区对用户可见?或者算法核心的CAS(或其他类似的)原语是否自动提供障碍?
从语义上讲,将数据推送到并发队列至少应该有一个释放围栏,并且从队列中弹出至少应该有一个获取围栏。我相信一个好的无锁实现不应该对其用户施加关于内存栅栏等的关注。即使无锁算法没有自动将栅栏放入适当的位置(或者不是针对每个架构),实现而不是用户必须确保正确的可见性和排序。用户应该只关心选择“正常工作”的实现(可能/必须包括测试它确实有效):)