Reputation: 4406
Assume we have two threads working with a method that execute below:
while(true){
if(Queue.Count() <= 0){
wait();
}
object anObject = Queue.Dequeue();
}
Now the problem occurs when Queue has one element init, Thread 1 is about to execute Queue.Count line, Thread 2 about is on Queue.Dequeue() and execution priority is on Thread 1.
As this situation occurs, Thread 1 will throw an exception because, Queue.Count() will return 1 and it will try to dequeue an object from an empty queue. How can I handle this? What is the best solution if I want to dequeue safely? Should I use syncronized or lock something?
Best regards, Kemal
Upvotes: 0
Views: 605
Reputation: 5493
You can use thread safe queue ConcurrentQueue.
or if you don't want to use it
while (true)
{
Monitor.Enter(lockObj);
try
{
if (Queue.Count <= 0)
{
Monitor.Wait(lockObj);
}
object anObject = Queue.Dequeue();
}
finally
{
Monitor.Exit(lockObj);
}
}
or if using lock
while (true)
{
lock(lockObj)
{
if (Queue.Count <= 0)
{
Monitor.Wait(lockObj);
}
object anObject = Queue.Dequeue();
}
}
Upvotes: 1
Reputation: 18743
Lock the queue before accessing it.
lock (Queue) {
// blah blah
}
EDIT
while(true){
lock (Queue) {
if (Queue.Count() > 0) {
// Dequeue only if there is still something in the queue
object anObject = Queue.Dequeue();
}
}
}
Upvotes: 0
Reputation: 990
Try this pattern:
Producer
public void Produce(object o)
{
lock (_queueLock)
{
_queue.Enqueue(o);
Monitor.Pulse(_queueLock);
}
}
Consumer
public object Consume()
{
lock (_queueLock)
{
while (_queue.Count==0)
{
Monitor.Wait(_queueLock);
}
return _queue.Dequeue();
}
}
Upvotes: 0
Reputation: 51339
The best solution, assuming you are using .NET 4.0 or higher and really need a queue, is to switch to using ConcurrentQueue and it's TryDequeue method. ConcurrentQueue is thread safe.
That said, it looks from your code snippet like what you are really looking for is a thread safe producer/consumer queue. In that case, use the BlockingCollection class and it's Take method:
while(true){
// This will block until an item becomes available to take.
// It is also thread safe, and can be called by multiple
// threads simultaneously. When an item is added, only one
// waiting thread will Take() it
object anObject = myBlockingCollection.Take();
// do something with anObject
}
Upvotes: 2