is there enough information?
castironpi at gmail.com
castironpi at gmail.com
Tue Feb 26 08:07:48 EST 2008
> Create a class which will ensure
> turn-taking of events, using a get method with and integer index, by
> waiting for the prior index to complete before starting the next.
from thread import start_new_thread as launch
from threading import Lock
import time
from functools import partial
class WithObj:
def __init__( self, enter, exit ):
self.__enter__, self.__exit__= enter, exit
class Step:
def __init__( self ):
self._index= 0
self._locks= {}
self._opened= False
self._oplock= Lock()
def __getitem__( self, index ):
with self._oplock:
lock= self._locks.get( index, None )
if None is lock:
lock= self._locks[ index ]= Lock()
if index!= self._index:
assert lock.acquire( False )
return WithObj(
partial( self.ienter, index ),
partial( self.iexit, index ) )
def ienter( self, index ):
with self._oplock:
if self._opened:
return self
lock= self._locks.get( index )
assert lock.acquire()
with self._oplock:
return self
def iexit( self, index, *a ):
with self._oplock:
self._index+= 1
lock= self._locks.get( self._index )
if None is not lock:
lock.acquire( False )
lock.release()
def complete( self ):
with self._oplock:
self._index= 0
lock= self._locks.get( 0 )
if None is not lock:
lock.acquire( False )
lock.release()
def open( self ):
with self._oplock:
self._opened= True
for lock in self._locks.values():
lock.acquire( False )
lock.release()
class CustThread:
count= 0
def __init__( self ):
CustThread.count+= 1
self.id= CustThread.count
self.step= Step()
self.cont= True
self.cmd= None
self.ret= None
def __repr__( self ):
return '<CustThread %i>'% self.id
def thloop( thd ):
while thd.cont:
with thd.step[1]:
if not thd.cont: break
print( 'step 1', end= ' ' )
thd.ret= thd.cmd+ 1
with thd.step[3]:
print( 'step 3' )
thd.ret= None
thd.step.complete()
def op100( thd ):
with thd.step[0]:
print( 'step 0', end= ' ' )
thd.cmd= 100
with thd.step[2]:
print( 'step 2', end= ' ' )
ret1= thd.ret
assert ret1== 101
def main( func ):
if __name__== '__main__':
func()
@main
def fmain():
class Case:
def __init__( self ):
self.th1= CustThread()
while 1:
print( '===============================' )
class Case1:
case= Case()
launch( thloop, ( case.th1, ) )
for _ in range( 10 ):
case.th1.cmd= None
case.th1.ret= None
op100( case.th1 )
case.th1.cont= False
case.th1.step.open()
print( 'case complete' )
while 1: time.sleep( 1 )
'''
Kind of trivial, interesting technique, and general. Enter with
thd.step[n]: to indicate step n in a process. with thd.step[m] for m!
= n will block until it exits, and step[n+1] gets the go, or step[0]
with step.complete(). step.open() grants every step, such as in the
case of completion; set termination conditions prior to its call, and
check them in any sensitive loops.
One way to replace magic sequence numbers with meaning is the "Step1
Step2 Step3" style used in namedtuple, but they're only shown bare
here.
Sequence numbers are looked up in a hash; special applications can use
an array, and account for the possibility that with step[10]: may be
called before even step[0]. 0- and 1-based options are customizable.
Sequence length may be known at creation time; if so, the Step
instance can be initialized with it; contraindicating cases may
include with step[n] ... with step[n+2], that don't mean the right
thing in a separate instance.
__getitem__ returns a WithObj, calling __enter__ and __exit__ on which
routes to the Step instance, paired with the specified index. You
could probably cache those.
The example is a 1-SetOp, 2-DoOp, 1-GetReturn triplet.
acquire( False ) / release() pairs release a thread, whether it is
acquired already or not. _oplock synchronizes _index and lock lookup
operations across an instance.
Kind of cool.
'''
More information about the Python-list
mailing list