One just provides access to a database and seems to work fine.
The other object implements a producer consumer model, using a queue and seems to be were the problem lies. When the producer adds an element to the queue, it signals the consumer (each time). The consumer takes some time to run. Normally, this works fine. However, once every 10 or so times, it just doesn't work. Here's the producer section (Node qCurrent is the queue, queueRunner is the consumer thread):
lock(qCurrent.SyncRoot)
{
qCurrent.Enqueue(benchMe);
lastItemAdded = benchMe;
//Tell the sleeping thread that it has at least one benchmark to run
Monitor.Pulse(qCurrent.SyncRoot);
messages.WriteLine("We think we have pulsed the thread");
if(!queueRunner.IsAlive)
{
messages.WriteLine("Thread is dead for some readon");
messages.WriteLine(queueRunner.ThreadState.ToString());
}
else
{
messages.WriteLine("Thread is alive, why doesn't it work ");
}
}
Now the consumer thread:
//Runs forever
while(true)
{
//Make sure we have uninterupted access to the queue
lock(qCurrent.SyncRoot)
{
//if the queue is empty,
if(qCurrent.Count==0)
{
//wait until the queue is no longer empty
messages.WriteLine("We are now waiting for an item on the queue");
Monitor.Wait(qCurrent.SyncRoot);
messages.WriteLine("We have the lock again");
}
}
//Can't use the lock block because of scoping issues
//at least without being silly
Monitor.Enter(qCurrent.SyncRoot);
while(qCurrent.Count!=0)
{
//Get the lock for the currently running item and change it
Monitor.Enter(currentlyRunningLock);
currentlyRunning = (CBenchItem)qCurrent.Dequeue();
Monitor.Exit(currentlyRunningLock);
//Make sure we are no longer blocking the queue
Monitor.Exit(qCurrent.SyncRoot);
//Run the current element
runCurrent(currentlyRunning);
Monitor.Enter(qCurrent.SyncRoot);
}
Monitor.Exit(qCurrent.SyncRoot);
}
Now I expect to see something like this:
We are now waiting for an item on the queue
We think we have pulsed the thread
Thread is alive, why doesn't it work
We have the lock again
We are now waiting for an item on the queue
.
.
.
which I normally do, but sometimes I get this:
We are now waiting for an item on the queue
We think we have pulsed the thread
Thread is alive, why doesn't it work
We think we have pulsed the thread
Thread is alive, why doesn't it work
.
.
.
Notice that the consumer thread has not woken up!
When I inspect the queue itself, it will have the elements added to it
I should also mention, that though the producer is normally called remotely, it can also be called by a FileSystemWatcher that is local to the producer/consumer object.
Even when both are mixed however (regardless of which adds the first element), it normally works. I tried using PulseAll instead of pulse too, but no luck.
Yes these are the only threads running (at least unless remoting has created it's own somewhere) and the threads always collect locks in the same direction when multiple locks are required to avoid deadlock (which this doesn't seem to be anyway as one of the threads is still responsive).
I have the feeling this might be some sort of behavior of remoting I'm not familiar with, but I just don't know.
This is starting to drive me nuts, so any help would be much appreciated, thank you in advance,
-mwalts