2011-01-11 78 views
1

我有以下的輔助類(簡體):我可以擺脫此讀鎖嗎?

public static class Cache 
{ 
    private static readonly object _syncRoot = new object(); 
    private static Dictionary<Type, string> _lookup = new Dictionary<Type, string>(); 

    public static void Add(Type type, string value) 
    { 
     lock (_syncRoot) 
     { 
      _lookup.Add(type, value); 
     } 
    } 

    public static string Lookup(Type type) 
    { 
     string result; 

     lock (_syncRoot) 
     { 
      _lookup.TryGetValue(type, out result); 
     } 

     return result; 
    } 
} 

Add將被調用的應用程序大致10/100倍和Lookup將多個線程調用,許多十萬次。我想要的是擺脫讀鎖。

在這種情況下,您通常如何擺脫讀鎖?

我有以下觀點:

  1. 要求_lookup穩定的應用程序開始操作之前。可以從Attribute建立起來。這是通過屬性分配給的靜態構造函數自動完成的。要求上述要求我通過所有可能具有該屬性並且呼叫RuntimeHelpers.RunClassConstructor這是昂貴的操作的類型;

  2. 移至COW語義。

    public static void Add(Type type, string value) 
    { 
        lock (_syncRoot) 
        { 
         var lookup = new Dictionary<Type, string>(_lookup); 
    
         lookup.Add(type, value); 
    
         _lookup = lookup; 
        } 
    } 
    

    (隨着lock (_syncRoot)Lookup方法除去。)這種方法的問題是,這種使用的存儲器的不必要的量(這可能不會成爲一個問題),我可能會使_lookup揮發性的,但我我不知道這應該如何應用。 (John Skeets' comment here gives me pause.

  3. 使用ReaderWriterLock我相信這會讓事情變得更糟,因爲該地區被鎖定的很小。

建議是非常受歡迎的。

UPDATE:

緩存的值是不可改變的。

+0

您無法使用.NET 4及其中的併發集合嗎? – 2011-01-11 06:34:34

+0

對不起,.NET 2.0。 – 2011-01-11 06:49:08

回答

1

要完全刪除鎖定(稍微不同,然後「鎖定釋放」,其中鎖定幾乎消除並且其餘部分巧妙地用互鎖指令替換),您需要確保你的字典是不可變的。如果字典中的項目不是不可變的(並且結果是它們擁有鎖定),那麼您可能不應該擔心鎖定字典級別。

  1. 是最好的和最簡單的解決方案,如果你可以使用它。
  2. 合理且容易調試。 (注意:正如所寫的,它並不適用於同時添加同一項目。考慮雙重檢查鎖定模式,如果需要 - Double-checked locking in .NET
  3. 如果1/2是一個選項,我不會這樣做。

如果您可以使用新的4.0集合 - ConcurrentDictionary符合您的條件(請參閱http://msdn.microsoft.com/en-us/library/dd997305.aspxhttp://blogs.msdn.com/b/pfxteam/archive/2010/01/26/9953725.aspx)。

0

在目前的工作,所以沒有什麼高雅,想出了這個(未經測試)

public static class Cache 
{ 
    private static readonly object _syncRoot = new object(); 
    private static Dictionary<Type, string> _lookup = new Dictionary<Type, string>(); 

    public static class OneToManyLocker 
    { 
     private static readonly Object WriteLocker = new Object(); 
     private static readonly List<Object> ReadLockers = new List<Object>(); 
     private static readonly Object myLocker = new Object(); 

     public static Object GetLock(LockType lockType) 
     { 
      lock(WriteLocker) 
      { 
       if(lockType == LockType.Read) 
       { 
        var newReadLocker = new Object(); 
        lock(myLocker) 
        { 
         ReadLockers.Add(newReadLocker); 
        } 
        return newReadLocker; 
       } 

       foreach(var readLocker in ReadLockers) 
       { 
        lock(readLocker) { } 
       } 

       return WriteLocker; 
      } 
     } 

     public enum LockType {Read, Write}; 
    } 

    public static void Add(Type type, string value) 
    { 
     lock(OneToManyLocker.GetLock(OneToManyLocker.LockType.Write)) 
     { 
      _lookup.Add(type, value); 
     } 
    } 

    public static string Lookup(Type type) 
    { 
     string result; 
     lock (OneToManyLocker.GetLock(OneToManyLocker.LockType.Read)) 
     { 
      _lookup.TryGetValue(type, out result);  
     } 

     return result; 
    } 
} 

您將需要某種形式的清理爲讀儲物櫃,但應該是線程安全的,允許多個在讀同時也鎖定寫入的時間,除非我完全錯過了某些東西

+0

任何不使用http://msdn.microsoft.com/zh-cn/library/system.threading.readerwriterlock.aspx的原因?使事情變得更輕鬆。 – TomTom 2011-01-11 07:16:44