.NET には汎用の同期キューがないのはなぜですか?
-
01-07-2019 - |
質問
Queue.Synchronize を呼び出してスレッド セーフなキュー オブジェクトを取得できることに気付きましたが、同じメソッドは Queue<T> では使用できません。理由を知っている人はいますか?なんだか変なようですね。
解決
アップデート - .NET 4 では、 ConcurrentQueue<T>
ここに記載されているように、System.Collections.Concurrent 内 http://msdn.microsoft.com/en-us/library/dd267265.aspx. 。興味深いのは、その IsSynchronized メソッドが (正しく) false を返すことです。
ConcurrentQueue<T>
これは完全にゼロから書き直し、列挙するキューのコピーを作成し、次のような高度なロックなしテクニックを使用します。 Interlocked.CompareExchange()
そして Thread.SpinWait()
.
この回答の残りの部分は、古い Synchronize() および SyncRoot メンバーの廃止と、API の観点から見てうまく機能しなかった理由に関する限り、依然として関連性があります。
Zoaba のコメントによると、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 が変更される可能性があることに気づかないでしょう。
開発者に操作全体にわたって明示的なロック ステートメントの使用を強制することは、この誤ったセキュリティ感覚を防ぐことを意味します。
Brian が述べているように、SyncRoot の削除は、SyncRoot が主に Synchronized をサポートするために導入されたという理由もありましたが、多くの場合、ロック オブジェクトのより適切な選択があるためでもあります。ほとんどの場合、Queue インスタンス自体か、
private static object lockObjForQueueOperations = new object();
キューのインスタンスを所有するクラスで...
この後者のアプローチは、他の一般的なトラップを回避できるため、通常は最も安全です。
彼らが言うように、 糸通しが難しい, 、そしてそれを簡単に見せることは危険である可能性があります。
他のヒント
Parallel CTP をチェックしてみる価値があるかもしれません。これは、かなり話題になっている、この記事をまとめている人たちのブログエントリーです。
まったく同じではありませんが、より大きな問題が解決される可能性があります。(彼らはさえ使っています Queue<T>
対 ConcurrentQueue<T>
彼らの例として。)
現在、.Net 4.0 には次のものが存在します。
ConcurrentQueue<T>
System.Collections.Concurrent 内
(2 番目の Queue<T> を意味していると思います。)
IsSynchronized プロパティと SyncRoot プロパティ (ただし、Synchronise() は明示的には継承されない) が ICollection インターフェイスから継承されることを除いて、質問に具体的に答えることはできません。どの汎用コレクションもこれを使用せず、ICollection<T> インターフェイスには SyncRoot が含まれていません。
なぜこれが含まれていないのかについては、ライブラリ設計者が意図した方法で使用されていないか、単に新しいコレクションに保持することを正当化するほど十分に使用されていなかったと推測することしかできません。