0

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

1

4 Answers 4

2

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 } 
Sign up to request clarification or add additional context in comments.

1 Comment

When using a BlockingCollection in this context you can also use the GetConsumingEnumerable() method to replace the whole loop with a foreach loop, which reads better and even also supports a better end condition.
1

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(); } } 

1 Comment

Well actually I'm trying to understand the logic behind it, is there any good documentation about how we can do it regardless of programming language
0

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(); } } 

Comments

0

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(); } } } 

9 Comments

Using lock in this case might be inappropriate solution because we lock it and if the Queue.Count returns 0, thread will start to wait to be signaled and the other threads will wait because of lock implementation so deadlock will occur ??! :)
@kkocabiyik: What is wait() doing exactly? Why don't you dequeue only if Queue.Count() > 0?
Wait() actually stands for calling semaphore to wait that is bound to different threads. So that a thread signals to other threads back and forth.
So you already did a sort of lock implementation as I understand. It seems that only some if (Queue.Count() > 0) before dequeueing is missing then.
In addition to this, dequeueing only if Queue.Count() > 0 is not what I need. When you look at my case, I'm trying to realize what happens if thread 2 at 4th line and thread 1 is at 2 line and thread 1's turn. When thread 1's turn, Queue.Count() will return 1, and thread 2 will execute dequeue, and lastly thread 1 tries to dequeue empty queue
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.