Queue can result in nested monitor deadlock

Jonathan Amsterdam jbamsterdam at gmail.com
Mon Apr 17 10:32:06 EDT 2006


I think there's a slight design flaw in the Queue class that makes it
hard to avoid nested monitor deadlock. The problem is that the mutex
used by the Queue is not easy to change. You can then easily get
yourself into the following situation (nested monitor deadlock):

Say we have a class that contains a Queue and some other things. The
class's internals are protected by a mutex M. Initially the Queue is
empty. The only access to the queue is through this class.

Thread 1 locks M, then calls Queue.get(). It blocks. At this point the
Queue's mutex is released, but M is still held.

Thread 2 tries to put something in the Queue by calling the enclosing
class's methods, but it blocks on M. Deadlock.

The solution would be to expose the Queue's mutex via a constructor
argument and/or method, so that, to take the above example, one could
create M and give it to the Queue as its mutex. Of course this is
doable now, as the code below demonstrates. But it should be documented
and exposed.

As I'm new to the Python community, I'm not sure that this is the right
forum for this suggestion. Is it the sort of thing one would put on the
SourceForge bug list? Advice appreciated.

"Fixed" Queue class:

class LQueue(Queue.Queue):
    """
    Fixes a problem with the standard Queue implementation: you can't
use your own mutex,
    so you are subject to nested monitor deadlock.  This version lets
you pass in your
    own lock.
    """

    def __init__(self, maxsize=0, lock=None):
        "Optionally takes a lock (threading.Lock or threading.RLock) to
use for the queue's lock."
        Queue.Queue.__init__(self, maxsize)
        if lock:
            self.mutex = lock
            # Re-create the condition objects with the new mutex.
            self.not_empty = threading.Condition(self.mutex)
            self.not_full = threading.Condition(self.mutex)




More information about the Python-list mailing list