Locking and try/finally

Mike C. Fletcher mcfletch at rogers.com
Wed Dec 4 12:49:18 EST 2002


Another approach that makes resource-releasing w/out try-finally easy 
(but only works properly on CPython) is to create an object like this:

class MyLock( object ):
    def __init__( self, mutex ):
        self.mutex = mutex
        mutex.acquire()
    def __del__( self ):
        self.release()
    def release( self ):
        mutex = self.mutex
        # minor race condition possible here
        # not a problem if mutex.release can be
        # called multiple times w/out problem
        if mutex is not None:
            self.mutex = None
            mutex.release()

then use it like this:

def blah():
    """Generic use, whole function is locked"""
    lock = MyLock( mutex )
    return do_some_processing()
    # mutex is released when lock is destroyed

or

def blah2():
    """Show explicit release"""
    lock = MyLock( mutex )
    do_some_other_things()
    lock.release() # explicit release
    do_unlocked_things()
    lock = MyLock( mutex )
    return do_some_other_things_again()
    # lazy release again...
   
The basic idea being to use the local-variable finalisation of the 
function to do the finally clause equivalent. Unfortunately, Jython's GC 
approach is likely to make it untenable for use there.  Oh well.

The pattern (which isn't mine) is especially nice for system resources 
like OpenGL display-lists, where you want to store the resource for a 
while normally (i.e. lock in the given list), but de-allocate it 
immediately if the compilation function fails (in which case you just 
don't bother to store it), and need to ensure that the resource is freed 
on object deletion regardless.  Locks are a little less obviously suited 
to the pattern.

Enjoy,
Mike

Geoffrey Talvola wrote:

>xtian at toysinabag.com [mailto:xtian at toysinabag.com] wrote:
>...
>  
>
>>Obtaining locks is simpler in C++ than in Python. The equivalent
>>Python code is always 3 lines longer. In fact, about 9% of the Python
>>implementation of Recall is simply obtaining and releasing locks
>>safely. Yet, overall, the Python code is smaller.
>>    
>>
>...
>
>Instead of writing:
>
>	mutex.acquire()
>	try:
>		# do something
>	finally:
>		mutex.release()
>
>How about wrapping up the try/finally and acquire/release into a method of
>the mutex object that takes a callable as its argument:
>
>	def task():
>		# do something
>	mutex.call(task)
>
>This saves 2 lines, as long as the "do something" part can be placed into a
>nested function (which isn't always possible, but often is, using nested
>scopes).
>
>- Geoff
>
>  
>

-- 
_______________________________________
  Mike C. Fletcher
  Designer, VR Plumber, Coder
  http://members.rogers.com/mcfletch/







More information about the Python-list mailing list