2012-03-20 76 views
1

我一直在使用ReaderWriterLockSlim來同步讀/寫,到目前爲止效果很好。此ReaderWriterLockSlim鎖定模式是否正確?

我有一個對象的集合和讀/寫鎖保持在Dictionary<string, ReaderWriterLockSlim>。我有一個場景,我需要獲取多個讀鎖原子。我確定我沒有任何代碼可以允許一個線程同時持有多個寫鎖定,這讓我認爲下面的代碼可以毫無問題地工作。

如果我正在嘗試使用寫入鎖定而不是讀取鎖定的方法,我幾乎可以肯定我會以死鎖結束,除非我能確保鎖定始終以相同的順序發生(我不能在我的案件)。

有誰看到這個代碼的任何問題,假設有如下:

  1. 在其他地方,沒有線程持有寫鎖將被允許持有任何其他鎖(讀或寫)
  2. 多個線程可以持有任何數量的併發讀鎖

有什麼想法?

public void WithReaderLocksForItemsNamed(string[] itemNames, Action action) 
    { 
     // this gets locks for the items specified from my internation dictionary 
     ReaderWriterLockSlim[ ] locks = LocksForItemsNamed(itemNames) ; 

     try 
     { 
      foreach(var @lock in locks) 
      { 
       @lock.EnterReadLock() ; 
      } 

      action() ; 
     } 
     finally 
     { 
      foreach(var @lock in locks) 
      { 
       if (@lock.IsReadLockHeld) 
       { 
        @lock.ExitReadLock() ; 
       } 
      } 
     } 
    } 
+2

請問您能解釋爲什麼在同一個動作中使用多個鎖? – Scott 2012-03-20 17:26:29

+0

該行爲依賴於所有項目在執行時保持不變。 SQL世界中的一個例子是創建一個連接兩個表的視圖,並且我需要確保該操作不會失敗,因爲在創建視圖時引用表中的一個被更改。完全沒問題,如果這些表在事實發生變化之後... – 2012-03-20 17:31:00

+0

多個鎖的使用總是會導致死鎖的可能性。這實際上就是爲什麼ReaderWriterLockSlim存在的原因 - 解決同時使用兩個鎖來保護資源的問題。你用鎖保護什麼樣的資源?你的程序是大規模多線程的嗎? – Scott 2012-03-20 17:46:50

回答

0

這是一個老問題,但我認爲用最終的解決方案更新它仍然很好。雖然我從來沒有遇到過上述問題,但我採用了以相反順序退出鎖的謹慎做法。因此,最終代碼如下所示:

public void WithReaderLocksForItemsNamed(string[] itemNames, Action action) 
{ 
    // this gets locks for the items specified from my internation dictionary 
    ReaderWriterLockSlim[ ] locks = LocksForItemsNamed(itemNames) ; 

    try 
    { 
     foreach(var @lock in locks) 
     { 
      @lock.EnterReadLock() ; 
     } 

     action() ; 
    } 
    finally 
    { 
     foreach(var @lock in locks.Reverse()) 
     { 
      if (@lock.IsReadLockHeld) 
      { 
       @lock.ExitReadLock() ; 
      } 
     } 
    } 
} 
1

它看起來不錯,但您可能需要在方法本身,當然,一個在那裏你遍歷你的源列表,以獲得一個鎖重入鎖。