BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース データ構造の調整:.NETマルチスレッド化の新たなクラス

データ構造の調整:.NETマルチスレッド化の新たなクラス

ブックマーク

6月のParallel Extensions for .NET(source)のリリースにより、一連のクラスが追加され、マルチスレッドアプリケーションにおけるデータの共有がますます容易になった。新たな同期プリミティ ブ、機能およびコレクションクラスを含む10の新たなクラスに関して、それぞれについて簡単に触れることとするが、これが最初で最後である。

クラスの最初のバッチは、System.Threading名前空間にある。

CountdownEventが無限数のスレッド間の調整を可能にする。各スレッドが開始すると、カウンターはプリセットされるかインクリメントする。スレッドがタスクを完了すると、カウンターをデクリメントする。カウンターがゼロになるまで、CountdownEvent.Waitへの呼び出しによりメインスレッドはブロックされる。この意味では、CountdownEventAutoResetEventおよびManualResetEventと似ている。

基本的にLazyInitは、Futureと呼ばれているものである。LazyInitオブジェクトは、クラスや代行を受け取る。クラスを受け取ると、Valueプロパティが呼び出されたとき、デフォルトのコンストラクターで新しいインスタンスを作成する。代行が指定されると、代行の結果が格納されて、返される。

LazyInitには値の作成モードが3種類ある。AllowMultipleExecutionによって、各スレッドが最初に値を初期化しようとするが、必ず1つのオブジェクトのみが返される。その結果、複数のオブジェクトが作成されて、破棄されることにつながりかねない。EnsureSingleExecutionは、確実に1つのインスタンスのみが作成されるようにしている。最終的にThreadLocalは、各スレッドに別々のインスタンスを提供する。

WriteOnceは、LazyInitに替わるものと見ることができる。LazyInitのように、その値は一度のみ設定可能であり、その後は不変である。しかしながら、WriteOnceの値は外部からクラスへ割り当てられる。いったん設定されると、決して変わらない。

読み取り専用のセマンティクスが必要な場合、WriteOnceは特に便利である。しかしコンストラクターに値を割り当てる必要がないので、読み取り専用の修飾子を使用することはできない。 WriteOnceオブジェクトに複数回値を割り当てようとすると「破損」と表示され、二度と読み取りができなくなる。 Valueプロパティの代わりにTrySetValueを使用することで、この破損を防止することができる。

ManualResetEventSlimManualResetEventの軽バージョンである。旧バージョンと違い、カーネルオブジェクトに依存せず、終了化可能ではない。頻繁に作成される場合には、パフォーマンスの向上につながる。

ManualResetEventSlimのように、SemaphoreSlimはカーネルのシンラッパーを軽量のものと置き替える。

 

SpinLockおよびSpinWaitのさらに2つの軽量オブジェクトは、マルチコアおよびマルチプロセッサマシンに実に最適である。 両者共にブロック化スレッドをアクティブにし、本質的にCPUサイクルを浪費する。予想待機時間が非常に短く、コンテキストスイッチが障害になっている場合は便利である。

クラスの2番目のグループは、System.Threading.Collections名前空間にある。

ConcurrentQueueはマルチスレッドを考慮したキュー構造である。古いキュー、「スレッドセーフ」がロックを必要とする場合でさえ、Countプロパティを確認しアトミックアクションとしてDequeueを呼び出すことができる。ConcurrentQueueは、 TryDequeueメソッドを提供することのみによって、その落とし穴を避ける。数を確認せずに呼び出しても安全なので、明示的なロックを必要としない。

スタックセマンティクスでConcurrentStackは同様の動作をする。

複数の読み取りプログラムや書き出しプログラム向けに設計されたBlockingCollectionは、たいていは別々に実装する機能が多く装備されているため、やや複雑である。まず最初に、BlockingCollectionはコレクションとして単独で使用できる。またConcurrentStackConcurrentQueueのようなIConcurrentCollectionオブジェクトを折り返させることで、セマンティクスは変化する。

たいていのコレクションとは違い、BlockingCollectionGetConsumingEnumerableと いうメソッドのようなものをサポートする。これにより、コレクションに対してfor-eachループやLINQクエリーをスレッドセーフな方法で使用する ことができる。通常は、キューからアイテムを消費するような破壊的な操作は、どちらかの構造を使用している場合、例外を引き起こす。

書き出しプログラムを停止するには、BlockingCollectionsにサイズの上限を指定する。この限界を超えると、コレクションに追加する呼び出しがブロックされる。

BlockingCollectionsにも「コンプリート」しているという概念がある。CompleteAddingを呼び出す場合、コレクションには新たな項目は追加されないこと、および現在のバッチ終了後に処理を停止することができることが通知される。

最後に、BlockingCollectionsはグループでも使用可能である。オブジェクトをBlockingCollectionsの配列とともにAddAny?に渡す場合、オブジェクトはそのうちのどれか1つに付加される。ドキュメンテーションはまだ貧弱であるが、おそらくそれにより選択されたコレクションが最小である。すべてのコレクションがフルの場合、この呼び出しはブロックしている。

原文はこちらです:     http://www.infoq.com/news/2008/06/CDS

この記事に星をつける

おすすめ度
スタイル

BT