2017-01-11 10 views
2

私はConcurrentDictionaryの値としてIListを持っています。リスト内の値を更新するためにConcurrentDictionaryのリストを更新する

ConcurrentDictionary<int, IList<string>> list1 = new ConcurrentDictionary<int, IList<string>>; 

私はこれを行う:

しかし
if (list1.ContainsKey[key]) 
{ 
    IList<string> templist; 
    list1.TryGetValue(key, out templist); 
    templist.Add("helloworld"); 
} 

templist更新ConcurrentDictionaryに文字列を追加していますか?もしそうなら、データ破損が起こらないように、スレッドセーフな更新ですか?

または私はリストの代わりにConcurrentBagを使用した場合ConcurrentDictionary

EDIT

内部リストを更新または作成するためのより良い方法があるが、どのように私はこれを実装するのでしょうか?具体的には、どうすれば更新できますか? ConcurrentDictionaryのTryUpdateメソッドは少し過度に感じます。

ConcurrentBag.Addは、スレッドセーフなマンナでConcurrentDictionaryを更新しますか?

ConcurrentDictionary<int, ConcurrentBag<string>> list1 = new ConcurrentDictionary<int, ConcurrentBag<string>> 

答えて

2

まず、ContainsKey()TryGetValue()を実行する必要はありません。

あなたはこれを行う必要があります:実際に

IList<string> templist; 

if (list1.TryGetValue(key, out templist)) 
    templist.Add("helloworld"); 

あなたのコードを競合状態を持って書かれました。

ContainsKey()TryGetValue()を呼び出すスレッド間で、別のスレッドがそのキーで項目を削除している可能性があります。その後、TryGetValue()tempListをnullとして返し、tempList.Add()に電話するとnull参照例外が発生します。

第2に、はい:別のスレッドの問題が考えられます。辞書内に格納されているIList<string>がスレッドセーフであることはわかりません。

したがって、tempList.Add()を呼び出すことは安全であるとは限りません。

IList<string>の代わりにConcurrentQueue<string>を使用できます。これはおそらく最も堅牢なソリューションになるでしょう。

IList<string>へのアクセスをロックするだけでは十分ではないことに注意してください。

これは良くない:

if (list1.TryGetValue(key, out templist)) 
{ 
    lock (locker) 
    { 
     templist.Add("helloworld"); 
    } 
} 

あなたもIListにアクセスすることができることを他のどこでも同じロックを使用しない限り。これは達成するのは容易ではないので、ConcurrentQueue<>を使用するか、このクラスにロックを追加して、他のスレッドが基になるIListにアクセスできないようにアーキテクチャを変更してください。

1

スレッドセーフな辞書での操作は、キーによるスレッドセーフです。したがって、あなたの値(この場合はIList<T>)にアクセスする限り、1つのスレッドからしかアクセスできません。

ConcurrentDictionaryはではありません。は、同時に2つのスレッドが1つのキーに値する値にアクセスするのを防ぎます。

+0

私はdownvoterを質問します:私の答えをdownvoteしないでください?今はそれが私のように見えます。 – CodeCaster

+2

私はそれがあなただったと一瞬は考えなかった。私はあなたが常に下降音を説明することを知っている! :) –

0

ConcurrentDictionaryは、スレッドセーフな方法で値オブジェクトに変更を適用できるかどうかに影響しません。これは、値オブジェクト(あなたのケースではIList -implementation)の謝辞です。

No ConcurrentList<T> in .Net 4.0?の回答を見ると、.netにConcurrentListの実装が存在しない理由がいくつかあります。

基本的にスレッドセーフな変更を自分で処理する必要があります。最も簡単な方法は、ロック演算子を使用することです。例えば。

lock (templist) 
{ 
    templist.Add("hello world"); 
} 

もう1つの方法は、.netフレームワークでConcurrentBagを使用することです。しかし、この方法は、IListインターフェイスと項目の順序に依存しない場合にのみ、あなたにとって役に立ちます。

+0

私は質問を更新しました。 Bagのアップデートは辞書を更新しますか? –

-1

ConcurrentDictionary.AddOrUpdateメソッドを使用すると、アイテムをスレッドセーフな方法でリストに追加できます。そのシンプルでうまくいくはずです。

var list1 = new ConcurrentDictionary<int, IList<string>>(); 
list1.AddOrUpdate(key, 
     new List<string>() { "test" }, (k, l) => { l.Add("test"); return l;}); 
+1

申し訳ありませんが、ありがとうございます。今実際の実装についてコメントしてください:それでもスレッドの問題が発生します。 'AddOrUpdate()'が呼び出されたときに別のスレッドがリストを反復している場合はどうなりますか? – CodeCaster

+0

@CodeCaster明らかに、マルチスレッド環境で非スレッドセーフなデータ構造を使用している場合、これは安全ではありません。私はその質問がマルチスレッドの方法でリストに値を追加することだと思った。 OPがマルチスレッドの方法でリストにアクセスしたい場合、マルチスレッドのデータ構造を使用する必要があります。 – tym32167

+0

これを行うと、リストの変更はまだ安全ではありません。このコードは、問題のあるあらゆる種類の結果を可能にしながら、同時に複数のスレッドからリストを変更することにつながります。 – Servy

0

ConcurrentDictionaryを更新templistする文字列を追加していますか?

これはありません。

スレッドセーフなコレクション(ディクショナリ)は、スレッドセーフでないコレクション(IList)への参照を保持します。したがって、それらを変更することはスレッドセーフではありません。

ミューテックスの使用を検討することをお勧めします。

+0

引用したものとは別の質問に答えています。あなたの答えに反して、一時リスト*の更新は辞書からリストを取得する他のコンテキストから見ることができます。それはそうするのが安全でない理由です。 – Servy

+0

「観測可能です」は更新されているわけではありません。辞書は決してオブジェクトとして変更されません。これは、スレッドセーフではないコレクションへの参照を保持しています(もちろん、変更はすべて観察可能です)。しかし、それが安全でない理由でもあります。 – Mike

+0

そして、彼らの後の明確化に基づいて、彼らは明らかに、変更が同時辞書を通して観察可能であるかどうか尋ねていた。そして、ちょうど、辞書自体ではなく、辞書が参照するオブジェクトを変更しているということを明確にすることなく、質問に答えて「いいえ」と答えても、文脈では依然として誤解を招くほどです。 – Servy

0

ConcurrentBagのConcurrentDictionaryにはどのようなソリューションが最適なのかはすでに述べられています。ちょうどそれを行う方法を追加するつもりです

ConcurrentBag<string> bag= new ConcurrentBag<string>(); 
bag.Add("inputstring"); 
list1.AddOrUpdate(key,bag,(k,v)=>{ 
    v.Add("inputString"); 
    return v; 
}); 
関連する問題