我有一个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看起来并不完全像这样,有更多的节点和更多的代码,但问题是:
锁定节点后,锁定未被保持,有时。我不明白为什么。 有任何人的某种解释。
*有时意味着我无法知道它何时会发生。
答案 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新增的那个),并发现写锁未被保留,因此抛出异常。
这就是我认为正在发生的事情。