Queue.Synchronize を呼び出してスレッド セーフなキュー オブジェクトを取得できることに気付きましたが、Queue<T> では同じメソッドを使用できません。誰かが理由を知っていますか?ちょっと奇妙に思えます。
4 に答える
更新-.NET4では、 http:ConcurrentQueue<T>
//msdn.microsoft.com/en-us/library/dd267265.aspxに記載されているように、System.Collections.Concurrentにあります。そのIsSynchronizedメソッドが(正しく)falseを返すことに注意するのは興味深いことです。
ConcurrentQueue<T>
は完全に一から書き直し、列挙するキューのコピーを作成し、やなどの高度なロックなしの手法を使用しInterlocked.CompareExchange()
ますThread.SpinWait()
。
この回答の残りの部分は、古いSynchronize()およびSyncRootメンバーの廃止、およびAPIの観点からそれらがうまく機能しなかった理由に関連している限り、依然として関連性があります。
Zoobaのコメントによると、BCLチームは、あまりにも多くの開発者がSynchronize(および程度は低いがSyncRoot)の目的を誤解していると判断しました。
Brian Grunkemeyerは、数年前のBCLチームのブログでこれについて説明しました:http: //blogs.msdn.com/bclteam/archive/2005/03/15/396399.aspx
重要な問題は、ロックの粒度を正しく設定することです。一部の開発者は、「同期された」コレクションで複数のプロパティまたはメソッドを素朴に使用し、コードがスレッドセーフであると信じています。ブライアンは例としてキューを使用します。
if (queue.Count > 0) {
object obj = null;
try {
obj = queue.Dequeue();
開発者は、Dequeueが呼び出される前に、Countが別のスレッドによって変更される可能性があることに気づきませんでした。
開発者に操作全体で明示的なロックステートメントを使用するように強制することは、この誤った安心感を防ぐことを意味します。
ブライアンが述べているように、SyncRootの削除は、主にSynchronizedをサポートするために導入されたためですが、多くの場合、ロックオブジェクトのより良い選択があるためです-ほとんどの場合、Queueインスタンス自体または
private static object lockObjForQueueOperations = new object();
キューのインスタンスを所有するクラスで...
この後者のアプローチは、他の一般的なトラップを回避するため、通常は最も安全です。
彼らが言うように、糸通しは難しいです、そしてそれを簡単に見えるようにすることは危険かもしれません。
Parallel CTP はチェックする価値があるかもしれません。これは、かなり話題になっている、それをまとめている人たちからのブログエントリです。
まったく同じではありませんが、より大きな問題を解決する可能性があります。(彼らは例としてQueue<T>
vsを使っConcurrentQueue<T>
ています。)
現在、.Net 4.0 には次の 1 つがあります。
ConcurrentQueue<T>
System.Collections.Concurrent で
(2番目のものは Queue<T> を意味していると思います。)
IsSynchronized および SyncRoot プロパティ (明示的に Synchronise() ではない) が ICollection インターフェイスから継承されていることを除いて、私は具体的に質問に答えることができません。これを使用するジェネリック コレクションはなく、ICollection<T> インターフェイスには SyncRoot が含まれていません。
含まれていない理由については、ライブラリ設計者が意図した方法で使用されていなかったか、新しいコレクションに保持することを正当化するのに十分なほど使用されていなかったと推測することしかできません.