2012-09-12 35 views
1

我有一個AVL樹數據結構,其中每個節點都有自己的鎖。因爲有更多的作家試圖訪問一個節點。EnterWriteLock後不鎖定

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)); 
    } 

作家看起來不完全一樣,有更多節點和更多的代碼,但問題是以下幾點:

後鎖定節點,不鎖,有時。我不明白爲什麼。 有任何解釋。

*有時意味着我無法知道它何時會發生。

+0

將此代碼複製並粘貼到項目中很明顯,它不像您的真實代碼。其中有許多錯誤會阻止它編譯,如果它們以明顯的方式修復,則不會拋出異常。請嘗試創建一個簡短但完整的* compilable *示例來演示問題。 (你可能在嘗試這樣做的時候自己發現解決方案) –

+0

不,它不是一個真正的代碼,現在它是代碼,但是我仍然無法在這裏複製整個項目,因爲它太長了。這只是對問題的解釋。 – Dejvovo

+0

您持有寫鎖,而不是讀鎖。將測試更改爲ww.IsWriteLockHeld –

回答

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新建的目錄),並發現寫入鎖未保留,因此引發異常。

這就是我認爲正在發生的事情。

+0

感謝您的新觀點,但我相信,這不是問題。即使在更改遞歸策略之後,問題仍然存在。 – Dejvovo

+0

請參閱我編輯的回覆。 –

+0

非常感謝你,這是我犯的那種錯誤。修復如下:將參照複製到根寫入方法並使用此引用而不是根。 – Dejvovo