可变大小元素无锁队列

问题描述 投票:-1回答:1

我得到了渲染系统,现在让它成为单个生产者和单个消费者系统,生产者拥有逻辑对象,并且可以在那里更新状态,消费者拥有独立于逻辑对象进行渲染的图形对象,但是生产者在那里更新状态。 对象具有不同的类型和/或大小。

因此,我想做的是无锁队列,生产者将特定对象的状态序列化为原始内存以排队,而消费者从该队列反序列化其状态,但是我发现的所有c ++实现的无锁队列都是固定大小的。

这是好方法还是我可以做得更好?而且我想知道为什么找不到可变大小元素的无锁队列,实现它是否有任何基本问题?

澄清我不是问如何将数据存储在固定大小的loockfree队列中,而是在实现可变大小的无锁队列时是否存在根本问题。

c++ multithreading lock-free
1个回答
0
投票

我在问实现可变大小无锁队列是否存在根本问题。

是的,很明显,除非您基于链接列表。 (这将产生一个解除分配的问题:如何知道该节点的潜在读取器何时结束?很难,除非您使用的是Java之类的垃圾收集语言。)

大多数队列实现使用固定大小的数组作为带有原子计数器的循环缓冲区来声明一个插槽,并在每个插槽中使用序列号或其他内容,以便读者可以辨别某个插槽是否仅被部分写入。

例如Lock-free Progress Guarantees

为此,保存队列条目的容器必须是可索引的。


这实际上是[[合理的

,您可以从固定大小的字节缓冲区(最好是2的幂,因此取模很便宜))中切出可变长度的块,并将其用作循环缓冲区。您将拥有一个读/写字节位置,而不是一个读/写索引,并且仍然可以通过不让写位置通过读取位置来检查是否已满。]每个作家都必须预先知道他们需要保留的大小。与其将写入索引增加1,还不如将写入位置增加该大小。

但是读取端的效率会有所降低。不仅要尝试将1的读取索引增加1,还需要读取当前读取位置的大小,并尝试将CAS的读取位置增加这么多。

这意味着您必须阅读条目[[之前

“声明”它,以知道正确的大小是多少,因此在加载读取索引和尝试尝试CAS之间可能会有加载时延在它上面。

不过,我认为这不会带来正确性问题。通过比较读写位置,写端已经可以避免覆盖未读条目。在多作者/生产者队列中,作者还需要避免写声明但部分写的条目。嗯,这可能是免费发生的,因为读取位置始终早于任何此类条目。

我认为在某些地方为部分编写的条目可能会出现问题。也许对于部分阅读的条目,如果读者也需要更新序列号,以使作者知道条目不仅是已声明所有权,而是已经完成阅读。

That

将会是一个问题,因为阅读位置将具有移到那里,并且书写者回绕并赶上未读条目时,作者并不确切知道条目的开始位置。[如果您想尝试发明自己的无锁队列,从而避免了这种问题和其他问题,同时仍然比使用互斥锁更有效,则可以尝试。
© www.soinside.com 2019 - 2024. All rights reserved.