2011-01-11 5 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は何千回もの多くは、アプリケーションおよびLookupでおよそ10/100回は多くのスレッドによって呼び出されると呼ばれます。私が望むのは、読み取りロックを取り除くことです。

通常この状況では、どのように読み取りロックを解除しますか?

私は、次のアイデアを持っている:

  1. は、アプリケーションが動作を開始する前に_lookupが安定していることを要求します。Attributeからビルドすることができます。これは、属性が割り当てられている静的コンストラクターによって自動的に行われます。上記を要求するには、属性を持つ可能性のあるすべての型を調べて、高価な操作であるRuntimeHelpers.RunClassConstructorを呼び出す必要があります。

  2. COWセマンティクスに移動します。 (Lookup方法で削除lock (_syncRoot)付き。)

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

    これに伴う問題は、これが(問題ではないかもしれません)メモリの不必要な量を使用して、私はおそらく_lookupは揮発性になるだろうということですが、私これをどのように適用すべきかわかりません。 (John Skeets' comment here gives me pause.

  3. を使用する。私は、ロックされている領域が小さいため、これにより状況が悪化すると思います。

提案は大歓迎です。

UPDATE:キャッシュの

値は不変です。現時点では仕事で

+0

.NET 4およびその中のコンカレントコレクションを使用できませんか? –

+0

申し訳ありません、.NET 2.0。 –

答えて

1

ロックを完全に削除するには(ロックがほとんどなくなって残りがインターロックされた命令で巧妙に置き換えられる「ロックフリー」)あなたの辞書は不変です。ディクショナリ内の項目が不変でない場合(結果としてロックが所有されている場合)、おそらくディクショナリレベルのロックについて心配する必要はありません。

  1. は、使用できる場合は最も簡単で簡単な解決策です。
  2. デバッグが妥当で簡単です。 (注:書かれているように、同じアイテムを同時に追加するとうまく機能しません。必要に応じてダブルチェックロックパターンを考慮する - Double-checked locking in .NET
  3. 1/2がオプションの場合、私はそれをしません。

新しい4.0コレクション - ConcurrentDictionaryを使用できる場合は、条件(http://msdn.microsoft.com/en-us/library/dd997305.aspxおよびhttp://blogs.msdn.com/b/pfxteam/archive/2010/01/26/9953725.aspxを参照)と一致します。

+0

はい、値は不変です。 –

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/en-us/library/system.threading.readerwriterlock.aspx?物事をより簡単にする。 – TomTom

+0

正直言って、前にそのクラスについて聞いたことはありませんでしたが、はるかに良い解決策のように見えます。 – Rob

関連する問題