A lock that times out but doesn't poll

Jive someone at microsoft.com
Thu Nov 25 18:32:00 CET 2004


Okay, I've got a comment: How about some comments?  Maybe it's just me, but
I find the code a little hard to comprehend.

What's up with this?

Exception in thread Thread-456:
Traceback (most recent call last):
  File "C:\Python23\lib\threading.py", line 436, in __bootstrap
    self.run()
  File "C:\Python23\lib\threading.py", line 544, in run
    self.function(*self.args, **self.kwargs)
  File "C:\Python23\Scripts\foo.py", line 29, in break_lock
    sc.pl.release()
error: release unlocked lock

That crops up occasionally.

It's been a while, but as I recall, the tricky bit in implementing timed
locks with an alarm clock thread is seeing to it that threads that don't
time out waiting on a timed lock do not leave zombie alarm clock threads
running.  If you are not careful, they could proliferate and eat up system
resources.


"Antoon Pardon" <apardon at forel.vub.ac.be> wrote in message
news:slrncq5vvl.61m.apardon at rcpc42.vub.ac.be...
> The queue and condition class allow threads to wait only a limited
> time. However this currently is implemented by a polling loop.
>
> Now for those who like to avoid polling I have here a Tlock
> class that allows for a timeout but doesn't use polling.
>
> All comments are welcome.
>
>
> ----------------------- Tlock.py -------------------------------
>
> import threading
>
> class TimeOut(Exception):
>   pass
>
> class Tlock:
>
>   def __init__(self):
>
>     self.mutex = threading.Lock()
>     self.lktab = [threading.Lock()]
>
>
>   def acquire(self, timeout=None):
>
>     class SC:
>       pass
>
>
>     def break_lock(sc, mutex, tab):
>
>       mutex.acquire()
>       try:
>         try:
>           i = tab.index(sc.pl, 1)
>           del tab[i]
>           sc.broken = True
>           sc.pl.release()
>           sc.pl.release()
>         except ValueError:
>           pass
>       finally:
>         mutex.release()
>
>
>     self.mutex.acquire()
>     sc=SC()
>     sc.ll = threading.Lock()
>     sc.ll.acquire()
>     self.lktab.append(sc.ll)
>     sc.pl = self.lktab[-2]
>     sc.broken = False
>     if len(self.lktab) > 2 and timeout is not None:
>       tm = threading.Timer(timeout, break_lock,
>                            args=[sc, self.mutex, self.lktab])
>       tm.start()
>     else:
>       tm = None
>     self.mutex.release()
>     sc.pl.acquire()
>     if sc.broken:
>       raise TimeOut, "lock timed out"
>     else:
>       if tm is not None:
>         tm.cancel()
>
>
>   def release(self):
>
>     self.mutex.acquire()
>     self.lktab[0].release()
>     del self.lktab[0]
>     self.lktab[0].release()
>     self.mutex.release()
>
>
> if __name__ == "__main__":
>
>   from time import sleep
>   from random import randint
>
>   T = Tlock()
>
>   def thrd(Id):
>
>     for _ in xrange(100):
>       try:
>         print "Trying %d" % Id
>         T.acquire(randint(0,6))
>         print "Entering %d" % Id
>         sleep(randint(0,6))
>         print "Leaving %d" % Id
>         T.release()
>       except TimeOut, ErrId:
>         print "Failed %d" % Id
>       sleep(randint(0,6))
>
>
>   for i in xrange(5):
>     th = threading.Thread(target=thrd, args=(i,))
>     th.start()





More information about the Python-list mailing list