web-dev-qa-db-ja.com

ConcurrentDictionary TryRemoveがfalseを返すのはいつですか

ディクショナリに指定されたキーの値が含まれていない場合にのみfalseを返しますか、それとも、別のスレッドが何かを追加/更新するなど、スレッドの競合状態が原因でfalseを返しますか?

コード内の質問:

ConcurrentDictionary<int, string> cd = new ConcurrentDictionary<int, string>();

// This might fail if another thread is adding with key value of 1.
cd.TryAdd(1, "one"); 

// Will this ever fail if no other thread ever removes with the key value of 1?
cd.TryRemove(1); 

編集:指定されたキーの値が含まれていない場合にのみfalseを返すと思いますが、確実に確認したいと思います。

ミッチは正しいConcurrentDictionaryは競合状態に対して脆弱ではありませんが、あなたが尋ねている質問に対する答えは、キーが存在する場合はTryRemoveは機能し、trueを返します。

投稿したコードでは、TryRemoveは他の場所からアクセスされないローカル変数であるため、falsecdを返す方法はありません。しかし、他のコードにこのConcurrentDictionaryオブジェクトへの参照が与えられていて、別のスレッドでキーを削除している場合、TryRemovefalseを返す可能性があります。ただし、キーがすでに削除されているため、辞書に対して他のアクションが実行されていて、キーが何らかの理由で「スタック」されているためではありません。

74
Dan Tao

ConcurrentDictionary は競合状態の影響を受けません。それがあなたがそれを使う理由です。

戻り値

オブジェクトが正常に削除された場合はtrue。それ以外の場合はfalse。

6
Mitch Wheat

もう1つの注意点:

// This might fail if another thread is adding with key value of 1.
cd.TryAdd(1, "one"); 

このコメントは正しくなく、「試してみる」とはどういう意味かについて同じ誤解を受けている可能性があります。これは、同時に追加しようとする試みではなく、値がキー1ですでに追加されているかどうかです。

標準のDictionary<TKey,TValue>を検討してください。同等のコードは次のようになります。

if (!d.Contains(1))
    d.Add(1, "one");

これには2つの操作が必要です。 cdには、ContainsAddの呼び出しの間にキー1が追加された値が含まれる場合があるため、このようなAPIをスレッドセーフに設計する方法はありません。その結果、Addがスローされます。

並行コレクションには、これらのテストと実行のペアを単一のAPIの背後にある単一のアトミック操作に論理的にバンドルするAPIがあります。

1
Drew Noakes