1

我有一个 AVL 树数据结构,其中每个节点都有自己的锁。这是因为有更多的作者试图访问一个节点。

class Node
{
    public ReaderWriterLockSlim ww;
    // ...
    public Node()
    {
        ww = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
        // ...
    }
}
class AVL_tree
{
    public Node root;
    // ...
    public void Write(int value)
    {
        root = new Node();
        root.ww.EnterWriteLock();
        if (!root.ww.IsWriteLockHeld) throw new Exception("Why?");
        // ...
        root.ww.ExitWriteLock();
    }
}

每个作家都从新线程开始

class Program{
    public static AVL_Tree data;
    static void Main()
    {
        data = new AVL_Tree();
        List<Thread> vlakna = new List<Thread>();
        for (int i = 1; i < 10; i++)
            vlakna.Add(new Thread(Write));
        foreach (Thread vlakno in vlakna)
            vlakno.Start();
    }
    public static void Write() // Write some random data into the tree
    {
        Random rnd = new Random(DateTime.Now.Millisecond);
        data.Writer(rnd.Next(1, 999));
    }

Writer看起来不完全一样,节点多,代码多,但问题如下:

锁定节点后,有时不会持有锁。我不明白为什么。有人解释一下。

*有时意味着我不知道它什么时候会发生。

4

1 回答 1

3

您确定它正在被其他线程访问吗?如果是同一个线程递归地获取锁,它将被授予每个递归级别。

要查看是否是这种情况,请将锁递归策略更改为 NoRecursion 并查看是否出现异常。

[编辑]

这是另一个想法:你有一个竞争条件。

您启动的每个线程都在调用data.Write(),即AVL_tree.Write()。

在 AVL_tree.Write() 中,您分配了一个新的根节点。

让我们检查您的 AVL_tree.Write():

class AVL_tree
{
    public Node root;
    // ...
    public void Write(int value)
    {
        root = new Node();         // [A]
        root.ww.EnterWriteLock();  // [B]
        if (!root.ww.IsWriteLockHeld) throw new Exception("Why?"); // [C]
        // ...
        root.ww.ExitWriteLock();
    }
}

假设线程 1 已经执行到行 [B],并且即将执行行 [C]。

现在假设线程 2 出现并执行行 [A] 并且即将执行行 [B]。

此时,根字段已被一个新字段覆盖,一个尚未获得其写锁的字段。

现在想象线程 1 继续行 [C]。它查看根(现在是线程 2 更新的根),发现写锁没有被持有,因此抛出异常。

这就是我认为正在发生的事情。

于 2012-09-12T09:20:47.910 回答