web-dev-qa-db-ja.com

ConcurrentDictionary値へのlinqクエリはスレッドセーフですか?

次のコードがあるとしましょう:

ConcurrentDictionary<long, long> myDict= new ConcurrentDictionary<long, long>();

通常、キーによるすべてのアクセスはスレッドセーフですが、次のlinqクエリもスレッドセーフですか?ドキュメントに何も見つかりません: http://msdn.Microsoft.com/en-us/library/dd287226.aspx

if myDict.Values.Any(x => !x.HasPaid))
{
  return false
}
44
Chris

修正...いつValuesプロパティにアクセスしているのかわかりません。オブジェクト自体でLINQを使用する場合、スレッドセーフです。


LINQはGetEnumeratorメソッドを使用してアイテムをジッターします。

[〜#〜] msdn [〜#〜] から直接

ディクショナリから返された列挙子は、ディクショナリの読み取りと書き込みと同時に安全に使用できますが、ディクショナリの瞬間的なスナップショットを表すものではありません。列挙子を介して公開されるコンテンツには、GetEnumeratorが呼び出された後に辞書に加えられた変更が含まれる場合があります。

if myDict.Any(x => !x.Value.HasPaid))
{
  return false
}
40
chilltemp

すでに述べたように、ConcurrentDictionary.GetEnumerator()は、辞書の瞬間的なスナップショットを表していません。ただし、ConcurrentDictionary.Valuesは、瞬間的なスナップショットを作成します。

したがって、以下は同等ではありません。

myDict.Any(x => !x.Value.HasPaid)
myDict.Values.Any(x => !x.HasPaid)
37
Kevin

ConcurrentDictionaryの状態のドキュメント( [〜#〜] msdn [〜#〜] ):

ConcurrentDictionaryのすべてのパブリックメンバーと保護メンバーはスレッドセーフであり、複数のスレッドから同時に使用できます。

.ValuesプロパティはIColletionインターフェイスによって規定された実装であるため、パブリックであり、したがってスレッドセーフです。

11
Jan C. de Graaf

これまでのすべての回答は素晴らしく、役立つものですが、コメントの1つでDuneCatが指摘したリンクは強調されていると思います。

http://geekswithblogs.net/simonc/archive/2012/02/22/inside-the-concurrent-collections-concurrentdictionary.aspx

具体的には….

ロックレス:

  • TryGetValue
  • GetEnumerator
  • インデクサーゲッター
  • ContainsKey

すべてのロックを解除します(lockfull?):

  • カウント
  • IsEmpty
  • キー
  • 価値観
  • コピー先
  • ToArray
4
RJB