无锁队列中的内存管理

| 我们一直在寻找在我们的代码中使用无锁队列,以减少当前实现中单个生产者和使用者之间的锁争用。那里有很多队列实现,但是对于如何最好地管理节点的内存管理,我还不太清楚。 例如,生产者如下所示:
queue.Add( new WorkUnit(...) );
消费者看起来像:
WorkUnit* unit = queue.RemoveFront();
unit->Execute();
delete unit;
我们目前使用内存池进行分配。您会注意到,生产者分配了内存,而使用者则删除了它。由于我们正在使用池,因此我们需要向内存池添加另一个锁以正确保护它。首先,这似乎抵消了无锁队列的性能优势。 到目前为止,我认为我们的选择是: 实现无锁内存池。 转储内存池并依赖线程安全分配器。 我们还有其他选择吗?我们正在尝试避免实现无锁内存池,但是我们可以采取这种方式。 谢谢。     
已邀请:
        只有生产者才能创建对象并在不再需要它们时销毁它们。消费者只能使用对象并将其标记为已使用。这才是重点。在这种情况下,您不需要共享内存。这是我了解有效的无锁队列实现的唯一方法。 阅读这篇很棒的文章,详细描述这种算法。     
        另一种可能性是为每个线程有一个单独的内存池,因此只有一个线程正在使用堆,并且您可以避免为分配锁定。 这使您可以管理无锁功能来释放块。幸运的是,这很容易管理:您为每个堆维护一个空闲块的链表。您将块自身的地址放入链表的链接字段中(用作内存),然后用持有链表头的指针进行原子交换。     
        您应该看一下英特尔的TBB。我不知道商业项目要花多少钱,但是它们已经有并发队列,并发内存分配器之类的东西。 您的队列界面看上去也很狡猾-例如您的RemoveFront()调用-如果队列为空怎么办?
new
delete
调用看起来也很多余。英特尔的TBB和微软的PPL(包含在VS2010中)不会遇到这些问题。     
        我不确定您的要求到底是什么,但是如果您遇到这样的情况,即生产者创建数据并将其推送到队列中,并且您有一个使用此数据并使用它然后销毁它的单个消费者,那么您只需要执行安全队列或可以创建您自己的单个链表,在这种情况下,此链表是安全的。 创建列表元素 在列表元素中追加数据 将下一个元素的指针从null更改为列表元素(或其他语言中的等效元素) 使用方可以以任何方式实现,默认情况下,大多数链接列表对于这种操作都是安全的(但是请检查该实现) 在这种情况下,使用者应释放此内存,否则它可以以相同的方式返回到生产者设置预定义标志。生产者不需要检查所有标志(如果有超过1000个标志)来查找哪个存储桶是空闲的,但是可以像树一样实现此标志,从而启用log(n)搜索可用池。我确信这可以在O(1)时间内完成而无需锁定,但不知道如何     
        我也有同样的担忧,所以我写了我自己的无锁队列(单生产者,单消费者),它为您管理内存分配(它分配了一系列连续的块,有点像
std::vector
)。 我最近在GitHub上发布了代码。 (此外,我在我的博客上发布了有关此内容的信息。) 如果在堆栈上创建节点,将其入队,然后将其出队到堆栈上的另一个节点,则根本不需要使用指针/手动分配。此外,如果您的节点实现了用于构造和分配的移动语义,它将被自动移动,而不是复制:-)     

要回复问题请先登录注册