Queue <T> .Dequeue returns null

I have a scenario in which

  • multiple threads push data in line

  • only one thread processes data using the code below

code -

while ( Continue ) { while ( queue.Count > 0 ) { MyObj o = queue.Dequeue(); someProcess(o); } myAutoResetEvent.WaitOne(); } 

But sometimes queue.Dequeue () returns null in the above script. What gives?

+6
multithreading synchronization c #
source share
7 answers

You need to read this blog post .

In addition, there is a very minimal "channel" skeleton for communication between threads:

 public class Channel<T> { private readonly Queue<T> _queue = new Queue<T>(); public void Enqueue(T item) { lock (_queue) { _queue.Enqueue(item); if (_queue.Count == 1) Monitor.PulseAll(_queue); } } public T Dequeue() { lock (_queue) { while (_queue.Count == 0) Monitor.Wait(_queue); return _queue.Dequeue(); } } } 
+7
source share

You need to synchronize access to the queue. Put lock expressions around all sections of the code that access the queue (both read and write). If you access a queue from multiple threads at the same time, internal structures may be damaged and something may happen.

+8
source share

You speak:

multiple threads push data in line

The Queue<T>.Enqueue not thread safe. This means that the work is performed inside the Enqueue method, which must be synchronized if several threads are calling it. A simple example would be updating the Count property. This is a safe bet that somewhere in the Enqueue method Enqueue is a line that looks something like this:

 ++count; 

But, as we all know, this is not an atomic operation. It really looks more like this (in terms of what is actually happening):

 int newCount = count + 1; count = newCount; 

So let's say that Count is currently 5, and Thread 1 passes by int newCount = count + 1 ... then Thread 1 thinks: "OK, the count is now 5, so I'll do it." But the next operation that is performed is where Thread 2 falls into int newCount = count + 1 and thinks the same as Thread 1 ("the count is now 6"). Thus, two objects have just been added to the queue, but the count is only 5 to 6.

This is just a very simple example of how a non-thread-safe method, such as Queue<T>.Enqueue , can be confused when access is not synchronized. It does not specifically indicate what is happening in your question; my intention is simply to indicate that what you are doing is not thread safe and will lead to unexpected behavior .

+6
source share

Guffa is right, having multiple threads, reading and writing to the queue will cause problems because Queue <T> is not a reliable thread.

If you are using .NET 4, use the ConcurrentQueue <T> class, which is thread safe. If you are not on .NET 3 or earlier, you can either do your own locking, as Guff pointed out, or use a third-party library.

+4
source share

Make sure nothing is pressed null into the queue. null allowed as values ​​in the queue. Also, according to this document , only Queue<T> static members are thread safe, so beware of reading and writing to streams.

+2
source share

Why don't you solve the problem this way?

 while (IsRunning) { do { MyObj myObj = queue.Dequeue(); if (myObj != null) { DoSomethingWith(myObj); } } while (myObj != null); myAutoResetEvent.WaitOne(); } 

Update

Well, after reading the Earwickers comment and all the other answers, you're fine, and I'm just wrong. Therefore , please do not use the code above in multi-threaded contexts .

0
source share

If you are using a non-core queue (not what I recommend using it), you can use the Queue.Synchronized method to get a thread-safe shell:

 Queue queue = Queue.Synchronized(new Queue()); 

Otherwise, you must take care to lock yourself up, as others suggest.

0
source share

All Articles