32

The TryDequeue in ConcurrentQueue<T> will return false if no items in queue.

If the queue is empty I need that my queue will wait until new item to be added in queue and it dequeue that new one, and the process will continues like that.

Should I use Monitor.Enter, Wait, Pulse or any better options in C# 4.0?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
C-va
  • 2,910
  • 4
  • 27
  • 42
  • 3
    hmmm - it surprises me that this isn't conveniently exposed - it seems like a common use-case... – Marc Gravell Feb 16 '11 at 08:31
  • I think with 4.0 a BCL class should expose this, but if nothing else appears, perhaps look [at this answer](http://stackoverflow.com/questions/530211/creating-a-blocking-queuet-in-net/530228#530228), in which TryDequeue will block until *either* there is an item (returning `true`) *or* the queue is empty and explicitly shut down (returning `false`) – Marc Gravell Feb 16 '11 at 08:32
  • If the Queue is empty I need that my Thread will wait until new item to be added in queue and it dequeue that new one, and the process will continues like that. – C-va Feb 16 '11 at 08:34
  • @Marc : I need to resume my thread to dequeue atonce the new item is added. How can i achieve this. – C-va Feb 16 '11 at 08:40
  • 1
    the above does that, but it looks like "Damien_The_Unbeliever" has the answer here – Marc Gravell Feb 16 '11 at 09:04
  • Old question, but people coming here may also want to check out [this](http://stackoverflow.com/a/7868264/4289902) answer that suggests using a [BufferBlock](https://msdn.microsoft.com/en-us/library/mt604455(v=vs.110).aspx), which allows async waiting. – Jono Job Sep 22 '16 at 04:03

3 Answers3

55

Isn't this what BlockingCollection is designed for?

As I understand it, you can wrap your ConcurrentQueue with one of these, and then call Take.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
2

You can use BlockingCollection.

Do something like that:

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;
}
Yair Levi
  • 1,261
  • 10
  • 11
-2

You could periodically check the number of elements in the queue and when the number of elements is greater than zero, you give a signal using e.g. ManualResetEvent to the thread which dequeues the element(s) until the queue is empty.

Here is the pseudo code for this:

Check Thread:

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

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

Dequeue Thread:

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

Consider using lock in the DequeueUntilQueueEmpty, too.

Tomas Walek
  • 2,516
  • 2
  • 23
  • 37
  • 1
    Actually im using Monitor.enter,wait,pulseall to make the thread wait and signal. Is ManualResetEvent a better option? – C-va Feb 16 '11 at 09:36
  • Actually im using Monitor.enter,wait,pulseall to make the thread wait and signal. Is ManualResetEvent a better option? – C-va Feb 16 '11 at 09:45
  • ManualResetEvent is lightweight option, Monitor is a heavy one. – Tomas Walek Feb 17 '11 at 09:53