在EnterWriteLock之后,不保持锁定

时间:2012-09-12 09:08:49

标签: c# .net multithreading synchronization locking

我有一个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看起来并不完全像这样,有更多的节点和更多的代码,但问题是:

锁定节点后,锁定未被保持,有时。我不明白为什么。 有任何人的某种解释。

*有时意味着我无法知道它何时会发生。

1 个答案:

答案 0 :(得分: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新增的那个),并发现写锁未被保留,因此抛出异常。

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