无锁队列中的内存管理

时间:2011-06-23 22:14:37

标签: c++ lock-free

我们一直希望在代码中使用无锁队列来减少当前实现中单个生产者和使用者之间的锁争用。那里有很多队列实现,但我还不太清楚如何最好地管理节点的内存管理。

例如,制作人看起来像这样:

queue.Add( new WorkUnit(...) );

消费者看起来像:

WorkUnit* unit = queue.RemoveFront();
unit->Execute();
delete unit;

我们目前使用内存池进行分配。您会注意到生产者分配内存并且消费者删除它。由于我们正在使用池,因此我们需要向内存池添加另一个锁以正确保护它。这似乎首先否定了无锁队列的性能优势。

到目前为止,我认为我们的选择是:

  • 实现无锁内存池。
  • 转储内存池并依赖线程安全分配器。

我们可以探索其他任何选项吗?我们试图避免实现无锁内存池,但我们可能采取这种方式。

感谢。

5 个答案:

答案 0 :(得分:4)

只有生产者才能创建对象并在不再需要时销毁它们。消费者只能使用对象并将其标记为已使用。这才是重点。在这种情况下,您不需要共享内存。这是我知道高效无锁队列实现的唯一方法。

阅读详细描述此类算法的this篇文章。

答案 1 :(得分:1)

另一种可能性是为每个线程设置一个单独的内存池,因此只有一个线程使用堆,并且可以避免锁定分配。

这使您可以管理一个无锁功能来释放一个块。幸运的是,这很容易管理:您为每个堆维护一个空闲块的链接列表。您将块自己的地址放入(您将用作的内存)链接列表的链接字段,然后使用指向链接列表头部的指针进行原子交换。

答案 2 :(得分:0)

你应该看看英特尔的TBB。我不知道商业项目的成本是多少,但是它们已经有并发队列,并发内存分配器等等。

您的队列界面也看起来很狡猾 - 例如,您的RemoveFront()调用 - 如果队列为空怎么办? newdelete调用看起来也很冗余。英特尔的TBB和微软的PPL(包含在VS2010中)不会遇到这些问题。

答案 3 :(得分:0)

我不确定您的要求到底是什么,但是如果您有生产者创建数据并将此数据推送到队列的情况,并且您有单个消费者使用此数据并使用它然后销毁它,您只需要保护安全排队或您可以制作自己的单链表,在这种情况下是安全的。

  • 创建列表元素
  • 在列表元素中附加数据
  • 将下一个元素的指针从null更改为list元素(或其他语言中的等效元素)

消费者可以以任何方式实施,并且大多数链接列表默认为这种操作安全(但检查白色实现)

在这种情况下,消费者应该释放这个内存,或者它可以以相同的方式将其返回到生成器设置预定义标志。生产者不需要检查所有标志(如果有超过1000个标志)来查找哪个存储桶是空闲的,但是这个标志可以像树一样实现,使log(n)能够搜索可用的池。我确信这可以在没有锁定的情况下在O(1)时间内完成,但不知道如何

答案 4 :(得分:0)

我有完全相同的问题,所以我编写了自己的无锁队列(单生成器,单用户)来管理内存分配(它分配了一系列连续的块,类似于{{1 }})。

我最近发布了code on GitHub。 (另外,关于它我posted on my blog。)

如果在堆栈上创建节点,将其排队,然后将其出列到堆栈上的另一个节点,则根本不需要使用指针/手动分配。此外,如果您的节点实现构造和赋值的移动语义,它将自动移动而不是复制: - )