【问题标题】:Lock-free programming without linked lists无链表的无锁编程
【发布时间】:2016-12-08 16:36:04
【问题描述】:

我曾多次读到,链表充其量只是一种不适合通用用途的利基数据结构,因为它们的缓存局部性很差。然而,我所见过的几乎每个无锁数据结构的例子都使用了链表。 C++ Concurrency in ActionThe 例如,多处理器编程艺术在实现无锁堆栈和队列时使用链表。

在设计堆栈和队列等无锁容器时,有没有比链表更好的替代方案?

【问题讨论】:

  • 循环缓冲区是一种常见的数据结构,可以同时提供无锁和局部性。 (但它通常具有有限的容量。)
  • 您可以使用双端队列,它是链表和数组的混合体。想法是无锁链表很容易实现,而其他更复杂的数据结构有许多您必须考虑的极端情况。
  • @JorgeBellón 你有关于如何实现无锁 STL 类双端队列的资源吗?这对我来说似乎很难。
  • 恐怕提供原子性的硬件指令对缓存不友好,因此更改数据结构可能无济于事
  • @Slava 引起争用的算法由于缓存一致性协议的乒乓效应对缓存不友好,但如果存在lock-free cache-awareness 的概念,那将是有原因的。

标签: c++ multithreading linked-list


【解决方案1】:

在设计无锁容器时,有没有比链表更好的替代方案

是的,可能出于某些目的。链表只是最简单的东西,可以很好地推广到许多应用程序。


如果您使用单链表(在最简单的情况下),您可以填充一个完全没有同步问题的节点(= 多个线程可以同时填充节点),并且唯一同步的操作是头指针交换。

因此,尽管链表并未针对性能提出其他建议,但您可以看到这适用于任意大而复杂的节点,以及任意数量的生产者和消费者。

比较循环缓冲区:如果您有多个生产者,您需要一些方法来标记部分缓冲区保留(防止其他写入),然后才能读取。这是因为所有生产者都共享同一个缓冲区,而不是在自己的节点上工作。它是可行的,但本质上是非原子的,只是因为你不能像准备一个单独的节点一样准备 共享缓冲区的一部分 远离其他线程的窥探。

如果你只有一个生产者,这很容易,而且它确实比链表具有更好的局部性,但它显然不太通用

【讨论】:

    【解决方案2】:

    链表并不一定意味着缺乏局部性。如果列表中的所有节点都通过单一分配(C 中的 malloc)分配,那么所有节点的内存将是连续的,无论节点如何相互指向。如果 sizeof(node) * max_nodes_count 比较小,可能适合各种缓存级别。

    【讨论】:

    • 没错,但是你仍然有数据依赖,所以即使是连续相邻分配的节点遍历一个链表仍然比遍历一个向量更昂贵(取决于架构、YMMV 等)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-11
    • 1970-01-01
    • 1970-01-01
    • 2012-12-10
    • 1970-01-01
    相关资源
    最近更新 更多