(更多)在线程二叉树中旋转节点时的高效锁定

时间:2009-03-16 20:55:02

标签: c# multithreading data-structures concurrency tree

所以,我提出了这种方案,用于在二进制树中旋转时锁定节点,多个线程同时具有读取和写入访问权限,这涉及每次旋转锁定四个节点,这似乎是一个非常多?我认为某种方式更智能,然后我想出了一种方法来减少所需的锁定,但谷歌没有出现太多(我可能使用了错误的术语)。

这是我当前的方案,橙色和红色节点通过旋转移动或更改,需要锁定,绿色节点与受旋转影响的任何节点相邻,但不受其影响。

binary tree rotation

我认为必须有更好的方法来做到这一点,我的一个想法是拍摄受影响的四个节点的快照,在快照中旋转它们然后用快照节点替换当前节点(假设没有任何东西)在我进行旋转时改变了 - 这将允许我几乎锁定自由但我担心内存开销可能会很大,考虑到旋转是一个相当快速的操作(重新分配)三点)?

我想我正在寻找关于如何有效地做到这一点的指针(没有双关语)。

6 个答案:

答案 0 :(得分:4)

看看不可变的二叉树。您必须更改一些节点(每个节点到根节点),但这不会改变两个方向log n的插入的复杂性。实际上,它甚至可以提高性能,因为您不需要任何同步代码。

例如,Eric Lippert在C#中写了一些关于不可变avl树的帖子。最后一个是:Immutability in C# Part Nine: Academic? Plus my AVL tree implementation

答案 1 :(得分:1)

据我所知,无锁算法缺少引用计数,这使得它们的一般用法存在问题;

,你不知道你对一个元素的指针是否有效 - 也许这个元素消失了。

Valois'通过一些奇特的内存分配安排来解决这个问题在实践中无用

我能看到做无锁平衡树的唯一方法是使用修改后的MCAS,你也可以在其中增加/减少,这样你就可以保持引用计数。我没有看过是否可以用这种方式修改MCAS。

答案 2 :(得分:0)

对于整个数据结构,通常会有一个锁,因为锁本身通常会占用一些严重的资源。我猜你已经试图避免这种情况,这必须是一些非常专业的场景,你有很多CPU密集型工作线程不断更新树?

您可以通过使每N个节点共享一个锁来获得平衡。进入循环操作时,查找受影响节点使用的唯一锁定集。大多数时候它只是一把锁。

答案 3 :(得分:0)

最佳解决方案取决于您的应用。但是如果你有一个内存数据库的东西,你想要对它进行并发更新,并希望有非常细粒度的锁定,你也可以看看不需要像二叉树一样频繁的节点旋转的B树。它们也是自动平衡的,不像二叉树,它需要更多的旋转来维持平衡(例如Splay或AVL树)。

如果你想对树进行事务修改,你可以使用功能B树(Thomas Danecker称之为不可变树)。这些是“写时复制”二进制树,你需要锁定的唯一东西是根节点。所以你只需要一把锁。并且操作实际上具有与二叉树相同的复杂性,因为功能二进制树上的所有操作都是O(log n),并且每当您沿着任何树下降时,您都会花费相同的对数时间。

每个节点有一个锁定很可能不是正确的解决方案。

答案 4 :(得分:0)

John Valois'paper简要介绍了使用辅助节点实现二叉搜索树的方法。我在并发LinkedHashMap的design中使用辅助节点方法。您可以在CiteSeerX(一个非常宝贵的资源)上找到关于并发树的许多其他论文。除非真的有必要,否则我会偏离使用树作为并发数据集合,因为它们往往由于重新平衡而具有较差的并发特性。通常更实用的方法,如跳过列表,可以更好地运作。

答案 5 :(得分:0)

我在编写时使用部分副本使二进制树无锁读取。我在此处发布了一个不完整的实施http://groups.google.com/group/comp.programming.threads/msg/6c0775e9882516a2?hl=en&