我正在寻找一种方法来实现支持单个生产者和多个消费者的无锁队列数据结构。我看过Maged Michael和Michael Scott(1996)的经典方法,但他们的版本使用链表。我想要一个使用有界循环缓冲区的实现。什么东西使用原子变量?
另外,我不确定为什么这些经典方法是为需要大量动态内存管理的链表设计的。在多线程程序中,所有内存管理例程都是序列化的。我们不是通过将它们与动态数据结构结合使用来破坏无锁方法的好处吗?
我正在尝试使用英特尔64位架构上的pthread库在C / C ++中对此进行编码。
谢谢你, 希里什
答案 0 :(得分:9)
使用循环缓冲器需要锁定,因为需要阻塞以防止头部越过尾部。但是否则头部和尾部指针可以很容易地以原子方式更新。或者在某些情况下,缓冲区可能非常大,以至于覆盖不是问题。 (在现实生活中,你会在自动交易系统中看到这一点,循环缓冲区的大小可以容纳X分钟的市场数据。如果你落后X分钟,你会比覆盖你的缓冲区更糟糕的问题)。
当我在C ++中实现MS队列时,我使用堆栈构建了一个无锁分配器,这很容易实现。如果我有MSQueue,那么在编译时我知道sizeof(MSQueue :: node)。然后我制作一堆所需大小的N个缓冲区。 N可以增长,即如果pop()返回null,很容易向堆请求更多的块,并将它们推送到堆栈上。在可能阻塞的更多内存调用之外,这是一个无锁操作。
请注意,T不能有非重要的dtor。我研究过一个允许非平凡dtors的版本,实际上是有效的。但我发现将T指向我想要的T,生产者释放所有权,消费者获得所有权更容易。这当然要求T本身是使用lockfree方法分配的,但是我在堆栈中使用的相同分配器也在这里工作。
无论如何,无锁编程的要点并不是数据结构本身更慢。要点是:
尽管如此,在许多情况下,基于锁定的方法是优选和/或必需的
答案 1 :(得分:3)
这是一个老问题,但没有人提供可接受的解决方案。所以我为其他可能正在搜索的人提供此信息。
提供一些非常有用的lockfree / waitfree数据结构,并提供详尽的解释。
您正在寻求的是读写器问题的无锁解决方案。
请参阅:http://www.1024cores.net/home/lock-free-algorithms/reader-writer-problem
答案 2 :(得分:1)
对于传统的单块循环缓冲区,我认为这不能通过原子操作安全地完成。你需要在一次阅读中做这么多。假设你有一个结构:
uint8_t* buf;
unsigned int size; // Actual max. buffer size
unsigned int length; // Actual stored data length (suppose in write prohibited from being > size)
unsigned int offset; // Start of current stored data
在阅读时你需要做以下事情(这是我实现它的方式,你可以交换一些步骤,比如我之后会讨论):
你应该做什么同步(如此原子)来使这项工作?实际上在一个原子步骤中组合步骤1和4,或澄清:执行此操作同步:
read_length=min(read_length,length);
length-=read_length
unsigned int local_offset = offset
offset+=read_length
之后你可以从local_offset开始做一个memcpy(或其他),检查你的读取是否超过循环缓冲区大小(分为2个memcpy),....这是“非常”线程安全的,你的写入方法仍然可以覆盖你正在读取的内存,所以要确保你的缓冲区足够大,以尽量减少这种可能性。
现在,虽然我可以想象你可以将3和4结合起来(我猜这是他们在链表实例中所做的),甚至是原子操作中的1和2,我看不到你在一个原子操作中完成这个整个交易:)。
但是,如果您的消费者非常聪明并且总是知道要阅读什么,您可以尝试放弃“长度”检查。你还需要一个新的woffset变量,因为用于确定写入偏移量的(offset + length)%size的旧方法将不再起作用。请注意,这与链表的情况很接近,实际上您总是从列表中读取一个元素(=固定的,已知大小)。在这里,如果你把它作为循环链表,你可以阅读很多或写到你当时正在阅读的位置!
最后:我的建议,只需要使用锁,我使用CircularBuffer类,完全安全的阅读&写一个实时的720p60视频流媒体,我没有锁定速度问题。
答案 3 :(得分:0)
这是一个古老的问题,但没有人提供准确答案的答案。鉴于(几乎)同一问题的搜索结果仍然很高,因此,应该存在一个答案。
可能有不止一种解决方案,但这是一种实现的解决方案: https://github.com/tudinfse/FFQ 自述文件中引用的会议论文详细介绍了该算法。