这是我的当前方案,橙色和红色节点被旋转移动或更改,需要锁定,绿色节点与任何受旋转影响的节点相邻,但本身不受影响。 二叉树旋转 我想肯定有更好的方法来做到这一点,我想到的一个想法是拍摄受影响的四个节点的快照,对它们进行旋转,然后用快照节点替换当前节点(假设我在旋转时没有发生任何变化)-这将使我几乎无需锁定,但我担心内存开销可能太大,考虑到旋转是一个相当快速的操作(重新分配三个指针)?
我想我正在寻找如何有效地完成此操作的指针。
log n
。实际上,这甚至可能提高性能,因为您不需要任何同步代码。就编程而言,无锁算法似乎缺乏引用计数,这使得它们的通用性受到问题的影响。你无法确定指向某个元素的指针是否有效 - 也许该元素已经消失了。
瓦洛伊通过一些奇特的内存分配方案来解决这个问题,但实际上并没有什么用处。
我所能想到的实现无锁平衡树的唯一方法是使用修改后的MCAS,其中你还可以进行增量/减量,以便维护引用计数。 我还没有查看过是否可以以这种方式修改MCAS。
通常整个数据结构只需要一个锁,因为锁本身通常会占用一些严重的资源。我猜想,由于您试图避免这种情况,这一定是一种非常专业的场景,其中有很多CPU密集型工作线程不断更新树?
您可以通过使每N个节点共享一个锁来获得平衡。在进入旋转操作时,找到受影响节点使用的唯一锁集合。大多数情况下,它只会是一个锁。
最佳解决方案取决于您的应用程序。但是,如果您有一个内存数据库,并且希望对其进行并发更新,并且希望具有非常细粒度的锁定,则还可以查看B树,因为它们不需要像二叉树那样经常进行节点旋转。与二叉树不同,它们也是自动平衡的,而二叉树需要更多的旋转来保持平衡(例如Splay或AVL树)。
如果您想对树进行事务性修改,则可以使用函数式B树(Thomas Danecker称之为不可变树)。这些是一种“写时复制”二叉树,唯一需要锁定的是根节点。因此,您只需要一个锁。在实践中,操作的复杂度与二叉树相同,因为所有函数式二叉树上的操作都是O(log n),并且每当您向下遍历任何树时,都会花费相同的对数时间。
每个节点都有一个锁最可能不是正确的解决方案。
我尝试使用部分写入复制(partial copy on write)使二叉树实现无锁读取。我在这里发布了一个不完整的实现http://groups.google.com/group/comp.programming.threads/msg/6c0775e9882516a2?hl=en&