15

C#のコレクションの背後にあるスレッドセーフ理論の概要を把握しようとしています。

Javaのように同時コレクションがないのはなぜですか?(java docs)。一部のコレクションはスレッドセーフのように見えますが、たとえば次の点に関して、どのような位置にあるのかは私にはわかりません。

  • 複合操作、
  • イテレータの使用の安全性、
  • 書き込み操作

車輪の再発明はしたくない!(私はマルチスレッドの第一人者ではなく、とにかくこれがどれほど難しいかを過小評価していません)。

コミュニティがお役に立てば幸いです。

4

3 に答える 3

29

.NETはこれまで比較的「低レベル」の同時実行性をサポートしてきましたが、.NET 4.0では、System.Collections.Concurrent安全で便利なさまざまなコレクションを含む名前空間が導入されています。

Andrewの答えは、もちろん.NET 4.0より前のコレクションの処理方法に関しては完全に正しいです。ほとんどの場合、「通常の」共有コレクションにアクセスするときに適切にロックします。ただし、同時収集により、プロデューサー/コンシューマーキューなどを簡単に使用できます。

于 2009-12-22T14:07:10.603 に答える
19

C#は、複数のスレッドにまたがるコレクションを操作するためのいくつかの方法を提供します。これらのテクニックをうまく説明するには、コレクションと同期(スレッドセーフ)から始めることをお勧めします。

デフォルトでは、Collectionsクラスは通常スレッドセーフではありません。複数の読者が自信を持ってコレクションを読むことができます。ただし、コレクションを変更すると、リーダースレッドを含め、コレクションにアクセスするすべてのスレッドに対して未定義の結果が生成されます。

コレクションクラスは、次のいずれかのメソッドを使用してスレッドセーフにすることができます。

  • Synchronizedメソッドを使用してスレッドセーフなラッパーを作成し、そのラッパーを介してコレクションに排他的にアクセスします。
  • クラスにSynchronizedメソッドがない場合は、クラスから派生し、SyncRootプロパティを使用してSynchronizedメソッドを実装します。
  • コレクションにアクセスするときは、SyncRootプロパティでC#のlockステートメント(Visual BasicではSyncLock)などのロックメカニズムを使用します。
于 2009-12-22T13:59:34.327 に答える
6

Jon Skeetが述べたように、.NET4のSystem.Collections.Concurrent名前空間に「スレッドセーフ」コレクションがあります。

以前の.NETFrameworkバージョンに同時コレクションが存在しない理由の1つは(少なくとも私の推測では)、同時コレクションを使用してもスレッドセーフを保証するのは非常に難しいためです。

(一部のコレクションは、非スレッドセーフコレクションからスレッドセーフコレクションを返すための同期メソッドを提供しているため、これは完全には当てはまりません。そのため、いくつかのスレッドセーフコレクションがあります...)

たとえば、スレッドセーフな辞書があるとします。キーが存在しない場合にのみ挿入したい場合は、最初にコレクションにクエリを実行してキーが存在するかどうかを確認し、キーが存在しない場合は挿入を実行します。ただし、これら2つの操作はスレッドセーフではありませんが、ContainsKeyのクエリとAdd操作の間に、別のスレッドがそのキーの挿入を実行した可能性があるため、競合状態が発生します。

言い換えると、コレクションの操作はスレッドセーフですが、コレクションの使用法は必ずしもそうではありません。この場合、スレッドの安全性を実現するには、従来のロック手法(mutex / monitor / semaphore ...)に戻す必要があります。そのため、同時収集では、マルチスレッドの安全性に関して何も購入されません(ただし、パフォーマンスの点でおそらく劣ります)。 。

于 2009-12-22T14:23:03.630 に答える