views:

61

answers:

3

I have observed that after an exception I have an object for which constructor is not called, which causes a lock to be held. What is the best way to improve the situation? Would calling del in an except block be the solution?

b=BigHash(DB_DIR, url)
meta = bdecode(b.get())
return meta

b holds a lock which is released on destruction (it's a C++ object) an exception is thrown by b.get().

+1  A: 

You need to do something like this to make sure b in unlocked

b=BigHash(DB_DIR, url)
try:
    meta = bdecode(b.get())
    return meta
finally:
    #unlock b here

A cleaner way would be if BigHash can work as a context, so you can write

with b as BigHash(DB_DIR, url):
    meta = bdecode(b.get())
    return meta

You might have to add some code to BigHash to make it work as a context though

gnibbler
Can't I use "with" or other language trick? From a C++ I find problematic that an object that falls out of scope isn't destructed.
piotr
@plotr, the object is destructed when it goes out of scope, but maybe it has modified the locked status of BigHash. Can you show the source for BigHash?
gnibbler
It's a couple of hundred lines of C++, so that would be impractical. The important thin is that the bucket is locked on constructor and unlocked on destructor. And python's GC seems to leave the object lying around.
piotr
You would not use `except` in this instance, you would use `finally`. You would not use a bare `except` (without a bare `raise`) in *any* instance.
Mike Graham
@Mike Graham, yes you are correct
gnibbler
@piotr, the size of the existing code doesn't matter, you'd just need to add `__enter__` and `__exit__` methods to make it work with `with`. Another way would be to wrap the class with a lock manager.
gnibbler
+3  A: 

No matter what, you want the lock to be released - whether or not an exception is thrown. In that case, it's probably best to release the lock/delete b in a finally: clause:

b=BigHash(DB_DIR, url)
try:
    meta = bdecode(b.get())
finally:
    del b # or whatever you need to do to release the lock
return meta

You could also use a context manager - http://docs.python.org/library/stdtypes.html#typecontextmanager. Simply add code to free the lock in the BigHash.__exit__ function, which will be called after leaving the with block in the following code:

with BigHash(DB_DIR, url) as b:
    meta = bdecode(b.get())
return meta
Daniel G
Thanks, couldn't mark both as answers, so +1
piotr
Surprisingly in python 2.5.4 this isn't working with "with".The destructor is not being called.
piotr
@piotr: Your BigHash class must have the `__exit__` method defined to play well with `with`. See http://docs.python.org/reference/datamodel.html#with-statement-context-managers
S.Lott
A: 

Calling del on a name is something you prettymuch never should do. Calling del does not guarantee anything useful about what will happen to the underlying object. You should never depend on a __del__ method for something you need to happen.

del only gets rid of one reference to an object, which can be confusing when you may have made more without thinking. Therefore, del is useful for cleaning up a namespace, not for controlling the lifetime of objects, and it's not even great for that—the proper way to control a name's lifetime is to put it in a function and have it go out of scope or put it in a with block.

You need to equip BigHash with the ability to release the lock explicitly, with an release or unlock or close method. If you want to use this with a context manager (with), you can define __exit__, which will get called at a predictable, useful time.

Mike Graham