2013-01-08 34 views
3

編輯:從我已經是答案,我的理解是,我提出的,不是真正的「不堵寫着」第一個解決方案,因爲只有一個線程可以進入升級鎖和寫鎖可以沒有被採取之前讀取被釋放...ReaderWriterLockSlim VS雙鎖格紋圖案

所以我的問題,如何使正確的方式是第一個解決方案是「非阻塞閱讀」創建如果不存在?


我想了解兩個解決方案的非阻塞多線程讀取。是什麼下面兩種解決方案之間的差異(也許我還是不明白一些事情,但我想):

/// <summary> 
/// ReaderWriterLockSlim pattern 
/// </summary> 
public class ReadWriteLockCheck 
{ 
    Dictionary<string, object> _dict = new Dictionary<string, object>(); 

    private ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); 

    public void CreateByKey(string key) 
    { 
     _rwLock.EnterReadLock(); 
     try 
     { 
      if (!_dict.ContainsKey(key)) //Non blocking read - Check if exists 
      { 
       _rwLock.EnterWriteLock(); //Lock 
       try 
       { 
        _dict.Add(key, new object()); 
       } 
       finally 
       { 
        _rwLock.ExitWriteLock(); 
       } 
      } 
     } 
     finally 
     { 
      _rwLock.ExitReadLock(); 
     } 
    } 

    public bool GetByKey(string key) 
    { 
     _rwLock.EnterWriteLock(); 
     try 
     { 
      if (_dict.ContainsKey(key)) //Non blocking read 
      { 
       return true; 
      } 

      return false; 
     } 
     finally 
     { 
      _rwLock.ExitReadLock(); 
     } 
    } 
} 

/// <summary> 
/// Double check lock pattern 
/// </summary> 
public class MonitorLock 
{ 
    Dictionary<string, object> _dict = new Dictionary<string, object>(); 

    private object _syncObj = new Object(); 

    public void CreateByKey(string key) 
    { 
     if (!_dict.ContainsKey(key)) //Non blocking read - Check if exists 
     { 
      Monitor.Enter(_syncObj); //Lock 
      try 
      { 
       if (!_dict.ContainsKey(key)) //Check if between first check and lock someone already added 
       { 
        _dict.Add(key, new object()); 
       } 
      } 
      finally 
      { 
       Monitor.Exit(_syncObj); 
      } 
     } 
    } 

    public bool GetByKey(string key) 
    { 
     if (_dict.ContainsKey(key)) //Non blocking read 
     { 
      return true; 
     } 

     return false; 
    } 
} 

,因爲它看起來對我來說,這兩種解決方案可以使非阻塞的讀取和僅阻塞時寫作......如果是這樣,ReaderWriterLockSlim的好處是什麼?正如我在google中發現的,MonitorReaderWriterLockSlim快得多。 當然我明白可能在閱讀時我會得到不正確的字典狀態,但對我來說沒問題。
感謝

+1

爲什麼不選擇一個已經發明輪子呢? 'System.Collections.Concurrent.ConcurrentDictionary '? http://msdn.microsoft.com/en-us/library/dd287191.aspx – spender

+0

使用'Monitor.Enter' /'Monitor.Exit'沒有什麼好處 - 只需使用'lock';除了*更簡單*之外,它還處理了一些邊緣情況(它可以使用不同的'Enter'重載) –

+0

@spender我看到了它,但是自.NET 4起可用的那個類,我們使用3.5 :( –

回答

4

From MSDN

只有一個線程可以在任何給定時間進入升級模式

基本上,你沒有做的不僅僅是使用全鎖更好 - 除了lock實際上會更快。

奇怪的是,這裏的一個好方法是Hashtable;特別是因爲值是object,而關鍵是引用類型(沒有額外的裝箱)。 Hashtable是不尋常的,讀取是完全線程安全的;你只需要防範多個作者

例如:

readonly Hashtable lookup = new Hashtable(); 

... 

object val = lookup[key]; // no need to synchronize when reading 

... 

lock(lookup) 
{ 
    lookup[key] = newVal; // synchronize when writing 
} 
+0

好吧,我明白了......如果我將更改_rwLock.EnterUpgradeableReadLock ();對_rwLock.EnterReadLock();它會有道理嗎?還有一點...你說Hashtable可以讀取線程安全模式....究竟是什麼意思?是否意味着當我使用Dictionary並試圖讀取值,我可以得到一些意想不到的問題,除了「不一致的對象狀態」? –

+0

@AlexDn重新第一次;如果您使用'EnterReadLock',您**必須**退出讀取鎖,然後再嘗試寫入鎖定;這兩者是完全分開的,關於後者:的確如此cording <,>'不**保證,所以對於字典你必須確保沒有作家,甚至只是做一個閱讀。是的:沒有,你會變得瘋狂。使用'Hashtable'你**不需要**;讀者只需閱讀 - 根本不需要同步*。只有作家需要同步。這大大簡化了事情。 –

+0

因此,當使用字典<,>無鎖時,我會得到一些例外嗎?或者在我的情況下可以做什麼樣的問題? –