thread.error: release unlocked lock

Tim Peters tim.peters at gmail.com
Sun Nov 21 01:21:20 EST 2004


[John P.Speno]
>>> I'm using the classic Python thread model. Main thread puts stuff
>>> into a Queue.Queue() and worker threads get stuff out of it and do
>>> their thing.

[Tim Peters]
>> A bounded queue or an unbounded queue?  Blocking get/put or
>> non-blocking get/put?  About how many items are in the queue?
>>  Since nobody has reported your symptom before, some detail or
>> other is going to be important.

[John]
> Thanks for asking. Here's what I can tell you.
>
> Unbounded queues with non-blocking get/put.

That's odd -- non-blocking put doesn't really make sense with an
unbounded queue, esp. when only one thread does put().  It will work
anyway, it's just peculiar.

So if the queue is unbounded, the put() method is the only code
anywhere that acquires or releases fsema.  That simplifies analysis,
but only in that it leads most directly to the conclusion that it's
impossible to get the error you're seeing.  The candidates remaining
are things like compiler optimization bugs, buggy platform threads,
buggy C extension modules.

You should really file a bug report, on Python's SourceForge tracker
-- there's already too much detail to keep straight in
email/newsgroup.

> At most there are 1500 items in the queue. There are 20 threads
> getting from the queue, and one putting.
>
> I did have bounded queues (max 40 items) and blocking puts but got
> the same insane error then too.

Since nobody else has reported this problem, a successful conclusion
is going to require analyzing a small-as-possible failing test case. 
I'm afraid that falls on you, unless someone else can reproduce your
symptom.  Here's a start, modeling one plausible set of guesses for
exactly what all the above means:

"""
import threading
import time
from Queue import Queue, Empty
from random import random

class Worker(threading.Thread):
    def run(self):
        while True:
            try:
                k = q.get_nowait()
                assert k == 1
            except Empty:
                pass
            time.sleep(random()/10.0)

q = Queue()
ts = [Worker() for dummy in range(20)]
for t in ts:
    t.start()

while True:
    if q.qsize() > 1500:
        print q.qsize()
        time.sleep(3)
    q.put_nowait(1)
    time.sleep(0.001)
"""

I can apparently run that all day under 2.3.4 (or 2.4c1, which has an
entirely different Queue implementation) and not see anything odd. 
Does it fail for you?  If not, how does it differ from what your app
does?  IOW, can you fiddle it so that it does fail?

>>  How do the standard test_thread, test_threading, and
>> test_queue tests fare on this box?  Was this Python configured to
>> use pthreads or native Solaris threads?

> % grep -i thread pyconfig.h | grep -v ^/
> #define HAVE_PTHREAD_H 1
> #define HAVE_PTHREAD_SIGMASK 1
> #define HAVE_THREAD_H 1
> #define PTHREAD_SYSTEM_SCHED_SUPPORTED 1
> #define SIZEOF_PTHREAD_T 4
> #define WITH_THREAD 1
> 
> I think that means it is using native Solaris threads, assuming my
> reading of thread.c is good.

I don't really know about Solaris config (another reason this would be
better in a bug report, where more people who care about bugs <wink>
would pay attention), but I'd *guess* it means you're using pthreads.

> All of test_thread, test_threading, and test_queue all passed.

That figures.  They check for sanity, but don't really count as stress tests.



More information about the Python-list mailing list