2017-02-03 20 views
0

私は、複数のスレッドがキューの要素に貢献するマルチスレッドのC#アプリケーションを構築しています。単一のスレッドが同じキューの要素を消費しています。私は、単一のスレッドが着信要素の要素のいくつかの縮小/マージを行うようにしたいので、理想的には、キュー上のすべての新しい要素を見て、それらを減らしてから、JavaのBlockingQueue.drainTo(Collection)メソッドに相当するC#はありますか?

while (true) 
{ 
    Collection<Elem> elements = queue.TakeAll(); 
    Collection<Elem> reducedElements = Reduce(elements); 
    for (Elem e in reducedElements) 
    { 
    process(e); 
    } 
} 

しかし、明らかにTakeAll()メソッドはありません。 Javaの経験から、私はBlockingQueue's drainTo methodに慣れています。興味のあるものを提供しています。

キューが空になるまで、TryTakeを使って何かを実装できます。しかし、それは、生産スレッドが潜在的に忙しいかもしれないというリスクを伴い、減らして処理するコレクションの有限の終了を引き起こす可能性があります。私は基本的にキューからすべてを取り出し、それを空のままにしながら作業できるコレクションを提供する方法を探しています。

+0

グッドAPI設計は、* *は含まれないものを知っている、追加するために何を知っていません。 TryDrainTo()と "この操作の動作は定義されていません..."は、確実に非常に早くカットリストに着陸させました。スレッドセーフは.NETフレーバの主要な設計目標でしたが、独自の(拡張)メソッドを追加したときにそれを見落とさないでください。 –

+0

さて、TryTakeAll()などの同様のメソッドを提供する可能性があります。今は、特定の時点で待ち行列にあるすべての要素を原子的に取り出す方法がないようです。私が要素を取り出す瞬間、同時に多くの要素がプロデューサによって追加される可能性があります。 –

答えて

0

名前空間System.Collections.ConcurrentのConcurrentQueueを見てください。

このキューは、スレッドセーフな操作のために作成されています。

拡張メソッドを簡単に追加できます。

public static class Extensions 
{ 
    public static List<T> DrainTo<T>(this System.Collections.Concurrent.ConcurrentQueue<T> poConcurrentQueue) 
    { 
     List<T> loList = new List<T>(); 
     T loElement; 
     while (poConcurrentQueue.TryDequeue(out loElement)) 
      loList.Add(loElement); 
     return loList; 
    } 
} 

次のように使用します。

System.Collections.Concurrent.ConcurrentQueue<string> loConcurrentQueue = new System.Collections.Concurrent.ConcurrentQueue<string>(); 

loConcurrentQueue.Enqueue("Element1"); 
loConcurrentQueue.Enqueue("Element2"); 

var loList = loConcurrentQueue.DrainTo(); 
+0

これは、drainToと同様の保証はありません。これは、すべての要素を原子的に取り除くことです。つまり、排水が停止するまでパブリッシャーは要素を追加することができません。その保証がなければ、忙しい出版のために待ち行列の終わりに到達することのない無限ループが発生する危険性があります。 –

関連する問題