2

ID プロパティを持つ項目の ConcurrentQueue と各項目のタスクの ConcurrentQueue を持つアプリがあります。キュー項目は次のようになります。

class QueueItem {
  public int ID { get; set; }
  public ConcurrentQueue<WorkItem> workItemQueue { get; set; }
}

キュー自体は次のようになります。

ConcurrentQueue<QueueItem> itemQueue;

itemQueue に対して foreach を実行するスレッドが 1 つあります。各キューからアイテムを deQueue し、それに対して作業を行います。

foreach(var queueItem in itemQueue) {
  WorkItem workItem;
  if (queueItem.workItemQueue.TryDequeue(out workItem))
    doWork(workItem);
  else
    // no more workItems for this queueItem
}

別のスレッドで itemQueue に queueItems を追加し、各 workItemQueue に workItems を追加する可能性があるため、ConcurrentQueues を使用しています。

私の問題は、queueItem に workItems がなくなったときに発生します - itemQueue からその queueItem を削除したい - のようなもの...

  if (queueItem.workItemQueue.TryDequeue(out workItem))
    doWork(workItem);
  else
    itemQueue.TryRemove(queueItem);

...しかし、私はそれを簡単に行う方法を見つけることができません。私が思いついた方法は、各 QueueItem をデキューし、workItemQueue にまだ WorkItems がある場合はそれをエンキューすることです。

for (int i = 0; i < itemQueue.Count; i++) {
  QueueItem item;
  itemQueue.TryDequeue(out queueItem);
  if (queueItem.workItemQueue.TryDequeue(out workItem)) {
    itemQueue.Enqueue(queueItem);
    doWork(workItem);
  }
  else
    break;
}

PFX ConcurrentQueue を使用して目的を達成するためのより良い方法はありますか、またはこれを行うための合理的な方法はありますか?カスタムの同時キュー/リストの実装を使用する必要がありますか、それとも何か不足していますか?

4

3 に答える 3

4

これは誰にとってもうまくいくとは限りませんが、同時実行キューからアイテムを削除するために私が思いついた解決策は次のとおりです。

私がしたことは、作業中のキューを一時的に空のものに置き換え、元をリストに変換してアイテムを削除し、変更されたリストから新しいキューを作成して元に戻すことでした。

コード内 (申し訳ありませんが、これは C# ではなく VB.net です):

Dim found As Boolean = False
//'Steal the queue for a second, wrap the rest in a try-finally block to make sure we give it back
Dim theCommandQueue = Interlocked.Exchange(_commandQueue, New ConcurrentQueue(Of Command))
Try
    Dim cmdList = theCommandQueue.ToList()
    For Each item In cmdList
        If item Is whateverYouAreLookingFor Then
            cmdList.Remove(item)
            found = True
        End If
    Next
    //'If we found the item(s) we were looking for, create a new queue from the modified list.
    If found Then
        theCommandQueue = New ConcurrentQueue(Of Command)(cmdList)
    End If
Finally
    //'always put the queue back where we found it
    Interlocked.Exchange(_commandQueue, theCommandQueue)
End Try

余談: これは私の最初の回答です。編集に関するアドバイスを投稿したり、私の回答を編集したりしてください。

于 2013-08-23T15:14:26.430 に答える
0

キューは、FIFO スタイルでアイテムを処理したい場合、つまり LIFO のスタックを意味します。また、concurrentdictionary と concurrentbag もあります。キューが実際に必要なものであることを確認してください。コンカレントキューで foreach を実行することはないと思います。

おそらく必要なのは、ワークアイテム用の単一のキューです (共通のインターフェイスを使用し、インターフェイスでキューを作成します。インターフェイスは、必要に応じて後で再キャストできる継承された型を公開する必要があります)。ワークアイテムが親に属している場合、親へのキーを保持するプロパティを使用でき (キーの GUID を考慮してください)、親を並行辞書に保持し、必要に応じて参照/削除できます。

あなたが持っている方法でそれをしなければならない場合は、フラグを追加することを検討してください。次に、itemqueue 内のアイテムを「closed」などとマークして、キューから取り出されたときに無視されるようにします。

于 2014-08-06T20:28:40.983 に答える