Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# PulseAll doesn't wake sleeping threads

I have a situation, where sometimes sleeping threads are not woken on a Monitor.PulseAll(object lock) command. The phenomenon is not deterministic. In general it works, but sometimes during debbuging, the sleeping threads fail to wake and my queue keeps filling up.

The working thread is put to sleep, if the queue is empty:

private void Dequeue()
{
    try
    {
        while (true)
        {
            T item;

            lock (_lock)
            {
                if (_queue.Count == 0)
                {
                    Monitor.Wait(_lock);  //thread stays asleep here. why?
                }
                item = _queue.Dequeue(); //break point [1]
            }
        }
    }
    catch (ThreadAbortException ex)
    {
        _logger.Error(ex)
    }
}

Upon Add the queue has at least one item and PulseAll on the lock-object should wake the threads.

public void Add(T item)
{
    Validate.NotNull(item, "item must not be null");

    lock (_lock)
    {
        _queue.Enqueue(item);
        _queueInfoAdministrator.IncrementCount();
        Monitor.PulseAll(_lock);
    }
}

Does anyone else have similar experiences or could point me in the right direction, as to why this happens (sometimes)?

EDIT 2011.04.08: Further information - there is only one consumer thread. So theoretically a Pulse would suffice. Once the state has been reached, where the consumer thread stays sleeping, I can continue to enqueue items and subsequently call PulseAll without being able to wake the sleeping thread. I placed a break point [1], which never gets hit in the described situation. Therefore I believe it is not a deadlock problem as described in the MSDN pages to Pulse/Monitor.

like image 920
froeschli Avatar asked Apr 20 '26 12:04

froeschli


1 Answers

Are you sure that the threads are asleep? Your code has a call to _queue.Dequeue, which is going to throw an exception if there are no items in the queue. So if two threads are waiting on the lock, when the Add method enqueues an item and calls PulseAll, both threads will be released. The first thread will call Dequeue and get the only item in the queue. The next thread will call Dequeue and throw an exception. If you're catching and swallowing that exception, you'll never see it. And since the exception has escaped the while loop, the thread terminates and the queue will begin to fill.

Also, although I doubt this is an issue in your case, see http://msdn.microsoft.com/en-us/library/system.threading.monitor.pulse.aspx, where it talks about potential deadlock using Pulse and PulseAll.

like image 72
Jim Mischel Avatar answered Apr 23 '26 01:04

Jim Mischel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!