Threading with a Queue

  • Thread starter Thread starter Cool Guy
  • Start date Start date
C

Cool Guy

The main thread of my application will add items to a queue, which another
thread will dequeue items from. This other thread will then perform a
blocking operation with each item it finds.

Is it possible to do this in a thread-safe manner?

I imagine something like this would work:

// ran in background thread
void DequeuerThreadMethod()
{
while (!Finished)
{
object item;
lock (queue)
{
item = queue.Dequeue();
}
DoBlockingOperation(item);

lock (queue)
{
if (queue.Count == 0)
SuspendThisThread();
}
}
}

// ran in main application thread
void AddToQueue(object item)
{
lock (queue)
{
queue.Enqueue(item);
}
ResumeDequeuerThread();
}

Will this be thread-safe?
 
Cool Guy said:
The main thread of my application will add items to a queue, which another
thread will dequeue items from. This other thread will then perform a
blocking operation with each item it finds.

Is it possible to do this in a thread-safe manner?

Absolutely - but it's better to use Monitor.Wait/Pulse than suspending
and resuming the thread directly.

See half way down
http://www.pobox.com/~skeet/csharp/threads/deadlocks.shtml
for some sample code.
 
Cool Guy said:
I have a question on that. Why is there a while clause in
ProducerConsumer.Consume, instead of an if clause? Is it possible for
queue.Count to be 0 when Monitor.Wait exits, considering the implementation
of that class?

Yes - consider the case where there are two threads consuming work
items, and one producing.


Consumer 1 Consumer 2 Producer

Enter listLock
queue.Count==0 - yes
Wait for listLock

Enter listLock

Enter listLock (start)

Queue item
queue.Count==1 - yes
Pulse listLock
Exit listLock

Enter listLock (complete)
queue.Count==0 - no
Dequeue item
Exit listLock

Wake up
Reaquire listLock
queue.Count is still 0, so need to wait again
 
Jon Skeet said:
Consumer 1 Consumer 2 Producer

Enter listLock
queue.Count==0 - yes
Wait for listLock

Enter listLock

Enter listLock (start)

Queue item
queue.Count==1 - yes
Pulse listLock
Exit listLock

Enter listLock (complete)
queue.Count==0 - no
Dequeue item
Exit listLock

Wake up
Reaquire listLock
queue.Count is still 0, so need to wait again

Ah, of course! My confused arose by me thinking that the call to
Monitor.Pulse would make the call to Monitor.Wait return immediately --
before anything else aquires a lock.

Jon, when I look up 'helpful' in the dictionary, there is a picture of you.
;-) Thanks!
 
Back
Top