2013-06-25 3 views
7

ConcurrentDictionary Pitfall - Are delegates factories from GetOrAdd and AddOrUpdate synchronized? AddOrUpdateはアトミックではないことを示しています(代理人が複数回実行されることは保証できません)。atomic addorupdate(同時辞書を使用して名前付きロッカーを作成しようとしています)

私は同時辞書ラhereを使用して実装をロック名を実装しようとしていますが、辞書は、このように、永遠に成長しないはずです。ここで

public class ConcurrentDictionaryNamedLocker : INamedLocker 
{ 
    // the IntObject values serve as the locks and the counter for how many RunWithLock jobs 
    // are about to enter or have entered the critical section. 
    private readonly ConcurrentDictionary<string, IntObject> _lockDict = new ConcurrentDictionary<string, IntObject>(); 
    private static readonly IntObject One = new IntObject(1); 
    private readonly Func<string, IntObject, IntObject> _decrementFunc = (s, o) => o - 1; 
    private readonly Func<string, IntObject, IntObject> _incrementFunc = (s, o) => o + 1; 
    private readonly Func<string, IntObject> _oneFunc = s => new IntObject(1); 
    private readonly Func<string, IntObject> _zeroFunc = s => new IntObject(0); 

    public TResult RunWithLock<TResult>(string name, Func<TResult> body) 
    { 
     name = name.ToLower(); 
     TResult toReturn; 
     lock (_lockDict.AddOrUpdate(name, _oneFunc, _incrementFunc)) 
     { 
      toReturn = body(); 
      if (!_lockDict.TryRemove(name, One)) 
       _lockDict.AddOrUpdate(name, _zeroFunc, _decrementFunc); 
     } 
     return toReturn; 
    } 

    public void RunWithLock(string name, Action body) 
    { 
     name = name.ToLower(); 
     lock (_lockDict.AddOrUpdate(name, _oneFunc, _incrementFunc)) 
     { 
      body(); 
      if (!_lockDict.TryRemove(name, One)) 
       _lockDict.AddOrUpdate(name, _zeroFunc, _decrementFunc); 
     } 
    } 
} 

しかし、問題はAddOrUpdateがアトミックではないですだから、競合が起きたときにエントリが削除されないことがしばしばあります。私はかなり確信していますが、AddOrUpdateがアトミックな場合、上記のコードはその仕事を行い、エントリーは適切に削除されます。

hereと記載されているキー+値拡張メソッドTryRemove(key、val)による条件付き削除の使用に注目してください。また、IntObjectはintの簡単な可変オブジェクトラッパーです。

私のオプションは何ですか? 1.原子条件付き(キーと値による)削除を持つ並行ディクショナリ実装がありますか?2. AddOrUpdateはアトミックであり、デリゲートが複数回実行されないようにしますか?

他にアイデアはありますか?名前付きロッカーが高速であることを望みますが、無制限のロック名前空間が与えられても、与えられた名前ではあまり競合しないので、メモリ圧迫の問題はありません。私が知る限り、文字列インターンシップは名前によって永遠に成長し、決してクリーンアップされず、その他の副作用があります。ミューテックスは半スローで、さまざまな迷惑行為(260文字制限)があります。

+0

あなたはこの答えで説明したように 'ConcurrentDictionary 'とタイプされた辞書を使用する可能性があります。http://stackoverflow.com/a/12611341/1236734 –

答えて

1

IntValueの正確なコードは、AddOrUpdateデリゲートで実行されているコードと同じです。

私はこの問題は、コードがIntValueインスタンスの両方であることを期待することであると思う:(参照カウントは、後増分にもかかわらず)

  • 不変

    • 変更可能な各文字列に関連付けられた単一IntValueインスタンスをロックするために

    除去基準として静的One作品へIntValue Sを比較する私は、コードを変更した場合ようになるように...

    private readonly Func<string, IntObject> _zeroFunc = s => IntObject.Zero; 
    

    public void RunWithLock(string name, Action body) 
    { 
        name = name.ToLower(); 
        lock (_lockDict.AddOrUpdate(name, _oneFunc, _incrementFunc)) 
        { 
         body(); 
         _lockDict.AddOrUpdate(name, _zeroFunc, _decrementFunc); 
         _lockDict.TryRemove(name, IntObject.Zero); 
        } 
    } 
    

    しかし、私はこのようなIntValueメソッドを実装することを選んだと非事業者として:が、これは動作するように思われる不変のゼロをサポートしています

    internal IntObject Dec(int p) 
        { 
         var newVal = Interlocked.Decrement(ref value); 
         if (newVal == 0) return Zero; 
         return this; 
        } 
    
  • 関連する問題