web-dev-qa-db-ja.com

ConcurrentQueueでデキューしてみてください

キューにアイテムがない場合、ConcurrentQueueのTryDequeueはfalseを返します。

キューが空の場合、新しいアイテムがキューに追加されるまでキューが待機し、その新しいアイテムがデキューされる必要があります。プロセスはそのように続行されます。

C#4.0でmonitor.enter、wait、Pulse、またはその他のオプションを使用する必要があります

24
C-va

これは BlockingCollection の目的ではありませんか?

私が理解しているように、ConcurrentQueueをこれらのいずれかでラップしてから、 Take を呼び出すことができます。

46

BlockingCollection を使用できます。

そのようなことをしてください:

private BlockingCollection<string> rowsQueue;
private void ProcessFiles() {
   this.rowsQueue = new BlockingCollection<string>(new ConcurrentBag<string>(), 1000);
   ReadFiles(new List<string>() { "file1.txt", "file2.txt" });


   while (!this.rowsQueue.IsCompleted || this.rowsQueue.Count > 0)
   {
       string line = this.rowsQueue.Take();

       // Do something
   }
}

private Task ReadFiles(List<string> fileNames)
{
    Task task = new Task(() =>
    {
        Parallel.ForEach(
        fileNames,
        new ParallelOptions
        {
            MaxDegreeOfParallelism = 10
        },
            (fileName) =>
            {
                using (StreamReader sr = File.OpenText(fileName))
                {
                    string line = String.Empty;
                    while ((line = sr.ReadLine()) != null)
                    {
                           this.rowsQueue.Add(line);
                    }
                }
            });

        this.rowsQueue.CompleteAdding();
    });

    task.Start();

    return task;
}
1
Yair Levi

キュー内の要素の数を定期的にチェックでき、要素の数がゼロより大きい場合は、たとえば、キューが空になるまで要素をデキューするスレッドへのManualResetEvent。

これの擬似コードは次のとおりです。

スレッドを確認してください:

while(true)
{
  int QueueLength = 0;
  lock(Queue)
  {
    queueLength = Queue.Length;
  }

  if (Queue.Length > 0)
  {
    manualResetEvent.Set();
  }
  else
  {
    Thread.Sleep(...);
  }       
}    

スレッドのデキュー:

while(true)
{
  if(manualResetEvent.WaitOne(timeout))
  {
    DequeueUntilQueueEmpty();
  }
}

DequeueUntilQueueEmptyでもロックを使用することを検討してください。

0
Tomas Walek