2017-02-01 3 views
0

ディクショナリ用の次の簡単なゲッタとセッタには、スレッドセーフティメカニズムが必要ですか?この場合、スレッドの安全性が懸念されますか?

必要な場合は、ロックとConcurrentDictionaryの両方の例を指定してください。

public virtual void Add(IFoo foo) 
    { 
     dictionary.Add(foo.name, foo); 
    } 

    public virtual IFoo Get(string name) 
    { 
     if (!dictionary.TryGetValue(name, out IFoo foo)) return null; 
     return foo; 
    } 

    public virtual bool Has(string name) 
    { 
     return dictionary.TryGetValue(name, out IFoo foo); 
    } 

    public virtual IFoo Remove(string name) 
    { 
     if (dictionary.TryGetValue(name, out IFoo foo)) 
     { 
      dictionary.Remove(name); 
     } 
     return foo; 
    } 

    protected readonly IDictionary<string, IFoo> dictionary = new Dictionary<string, IFoo>(); 
+3

なぜあなたはロックやConcurrentDictionaryを使用して独自の例を記述することはできません。

そしてここでは、ConcurrentDictionaryとバージョンです。このウェブサイトはコード作成サービスではありません。あなた自身の努力を示す必要があり、間違いを示すことができます。 –

+0

私の最初の質問は、本当に上記の場合にスレッドの安全性が必要ですか?いくつかのガイドラインで私に助言してください。 – user2727195

+1

このコードはどのように使われていますか?使用した実際のマルチスレッドコードを表示してください。 – fofik

答えて

1

要求通り、ここではロックを使用するスレッドセーフバージョンです。 Addメソッドは、競合が発生した場合に「最初の1つの勝利」または「最後の1つの勝利」を行うかどうかによって、GetOrAddまたはAddOrUpdateのいずれかを呼び出すことができます。

public virtual void Add(IFoo foo) 
{ 
    AddOrUpdate(foo); // If you want "last one wins" 
    //GetOrAdd(foo);  // If you want "first one wins" 
} 

private virtual IFoo GetOrAdd(IFoo foo) 
{ 
    return concurrentDictionary.GetOrAdd(foo.name, foo); 
} 
public virtual void AddOrUpdate(IFoo foo) 
{ 
    concurrentDictionary[foo.name] = foo; 
} 

public virtual IFoo Get(string name) 
{ 
    IFoo result; 
    concurrentDictionary.TryGetValue(name, out result); 
    return result; // will be null if TryGetValue returned false 
} 

public virtual bool Has(string name) 
{ 
    return concurrentDictionary.ContainsKey(name); 
    // But there's no guarantee it's still there when this method returns 
} 

public virtual IFoo Remove(string name) 
{ 
    IFoo result; 
    concurrentDictionary.TryRemove(name, out result); 
    return result; 
} 

private readonly ConcurrentDictionary<string, IFoo> concurrentDictionary = new ConcurrentDictionary<string, IFoo>(); 
+0

ありがとうジョー、最初の勝利と最後の勝利についてもっと説明がありますか? – user2727195

+0

"first one wins"は、2つのスレッドが同時にAddメソッドを呼び出すと、最初のものがディクショナリに項目を追加し、2番目のスレッドがその項目を追加しないことを意味します。 "最後のものが勝つ"とは、この状況では、最初のスレッドがそのアイテムを辞書に追加し、2番目のスレッドがそのアイテムを上書きすることを意味します。 ConcurrentDictionary.GetOrAddのMSDNのドキュメントをまだ読んでいない場合は、それを読んでください。 – Joe

+0

'しかし、このメソッドが返ってもそれがまだ残っているという保証はありません。だから、このコーナーをカバーするために何をお勧めしますか? – user2727195

0

あなたの辞書は、あなたが辞書については、以下をお読みください別のスレッドからアクセスされる場合は、次の

A辞書限り、コレクションが変更されないように、同時に複数のリーダーをサポートすることができます。それでも、コレクションを列挙することは、本質的にスレッドセーフな手順ではありません。まれに列挙型が書き込みアクセスと競合する場合は、列挙全体でコレクションをロックする必要があります。読み取りと書き込みのために複数のスレッドがコレクションにアクセスできるようにするには、独自の同期を実装する必要があります。

すべてのこれらの操作はアトミックであり、上の他のすべての操作に関して、スレッドセーフです:

私はそれは、原子およびスレッドセーフなメソッドを提供してスレッドセーフなコレクションとしてConcurrentDictionary<TKey, TValue>を使用することをお勧めConcurrentDictionaryクラス唯一の例外は、代理人を受け入れるメソッド、つまりAddOrUpdateとGetOrAddです。

チェックこのリンク:https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx

https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx

の代わりに、独自のロックコードを使用するが、しかし、あなたは、このリンクをチェックし、Dictionaryを使用したい場合は、スレッドの同期を実現するためにlock声明 を使用することができます

+0

"読み取りと書き込みのために複数のスレッドがコレクションにアクセスできるようにするには、独自の同期を実装する必要があります。これはConcurrentDictionaryにも当てはまりますか?上記の辞書がConcurrentDictionaryの場合、各add、get、remove関数でlock(this){}を使用するでしょうか? – user2727195

+0

ロックはDictionaryで使用できますが、ConcurrentDictionaryの場合はほとんどのメソッドでは必要ありませんが、唯一の例外はデリゲートを受け入れるメソッドです。 –

+0

ああ、あなたの編集が懸念を引き起こした、私はGetOrAddを使った別の質問がありました。私はそれをロックしたことはありません。 http://stackoverflow.com/questions/41865146/concurrency-with-reading-but-locking-with-mutating Code#2と#3のScottの答えをチェックしてください。 – user2727195

関連する問題