On Feb 29, 5:52 am, [EMAIL PROTECTED] wrote: > On Feb 29, 12:55 am, Dennis Lee Bieber <[EMAIL PROTECTED]> wrote: > > > On Thu, 28 Feb 2008 08:09:01 -0800 (PST), [EMAIL PROTECTED] declaimed > > the following in comp.lang.python: > > > > My goal is to return Deadlock from acquire() if its blocking would > > > directly create deadlock. Basic example: > > [ The safeguard is never worth the cost.] > > > I am NOT going to look any further into this line... > > I am.
Can anyone tell me if this deadlocks? Sample test block included, feel free to shred. Does not currently permit reentrance. Simplification of above, denies reentrant calls, eliminates ThreadDesc class. Getting a /beep/ on threaded printing in 3.0, none in 2.5. Got a case too, where 2444 == 2444 but 2444 is not 2444. Of course they aren't guaranteed to, but I am testing for identity in the return from thread.get_ident(). "The 'is' operator compares the identity of two objects." "[After] a = 1; b = 1, a and b may or may not refer to the same object." Humph. Anyway, without further ado, direct to you at no extra cost, thin and narrow for your cut-and-pasting convenience, drumroll please. -=-=-=-=-=-=-=- from __future__ import with_statement import threading import thread from time import sleep from collections import deque try: from collections import namedtuple ThreadLockPair= namedtuple( "ThreadLockPair", "thread lock" ) except: class ThreadLockPair: def __init__( self, thread, lock ): self.thread, self.lock= thread, lock Acquires, Deadlocks, Timesout= \ object(), object(), object() resultdict= { Acquires: 'Acquires', Deadlocks: 'Deadlocks', Timesout: 'Timesout' } class Trylock: _count= 0 _alllocks= set() _goplock= threading.Lock() def __init__( self, *ar, **kwar ): self._lock= threading.Lock() self._owner= None self._waiters= set() Trylock._alllocks.add( self ) self.id= Trylock._count Trylock._count+= 1 def __repr__( self ): return '<Trylock %i>'% self.id def acquire( self ): caller= thread.get_ident() with Trylock._goplock: if caller in self._waiters: return Deadlocks if self._cycles(): return Deadlocks self._waiters.add( caller ) assert self._lock.acquire() with Trylock._goplock: assert self._owner is None self._owner= caller return Acquires def release( self ): with Trylock._goplock: self._waiters.remove( self._owner ) self._owner= None self._lock.release() def __enter__( self ): if self.acquire() is Deadlock: raise Exception( 'Deadlock' ) def __exit__( self, t, v, tb ): self.release() def _cycles( self, thd= None ): lck= self if thd is None: thd= thread.get_ident() edges= [ ThreadLockPair( th, ck ) for ck in Trylock._alllocks for th in ck._waiters ] inpair= ThreadLockPair( thd, lck ) edges.append( inpair ) d= deque( [ e for e in edges if e.lock is lck ] ) while d: cur= d.popleft() locks= [ e.lock for e in edges if e.thread== cur.thread and e.lock is not cur.lock ] for ck in locks: nexts= [ e for e in edges if ck is e.lock and e.thread!= cur.thread ] if inpair in nexts: return True d.extend( nexts ) return False def main( func ): if __name__== '__main__': func() @main def fmain(): import random locks= [ Trylock() for _ in range( 20 ) ] def th1( i ): while 1: lock= random.choice( locks ) ret= lock.acquire() if ret is not Acquires: continue print( '%i th lock %s acquire\n'% ( i, lock ) ), sleep( .0001 ) lock2= random.choice( locks ) if lock2.acquire() is Acquires: print( '%i th lock2 %s acquire\n'% ( i, lock ) ), sleep( .0001 ) lock2.release() lock.release() print( '%i th lock %s release\n'% ( i, lock ) ), ths= [ threading.Thread( target= th1, args= ( i, ) ) for i in range( 6 ) ] [ th.start() for th in ths ] -=-=-=-=-=-=- -- http://mail.python.org/mailman/listinfo/python-list