Help Create Good Data Model
Carl Banks
invalidemail at aerojockey.com
Sat Mar 11 19:34:38 EST 2006
mwt wrote:
> def get_data(self, key):
> """Returns a COPY of <key> data element."""
> try:
> self.mutex.acquire()
> return copy.deepcopy(self.data[key])
> finally:
> self.mutex.release()
self.mutex.acquire() should be outside the try block, like this:
self.mutex.acquire()
try:
return copy.deepcopy(self.data[key])
finally:
self.mutex.release()
The reason is: what if the call to self.mutex.acquire fails (raises an
exception)?
Suppose that another thread (#1) has the mutex, and this thread (#2) is
waiting on it, when an exception is raised in it (say a timeout,
keyboard interrupt, or runtime error). What will happen? Because the
acquire call is inside the try block, the finally block gets run, and
thread #2 releases the mutex being held by #1. But wait! Now let's
say there's a third thread (#3) that's also waiting on this mutex.
When #2 releases the mutex, #3 runs. But #1 is not done... #3 corrupts
the data. You've just destroyed the secret plans. You're fired.
The same logic applies to open/close, allocate/deallocate, set/unset,
or any other resource acquisistion. Acquire the resource before the
try block, release it in the finally block.
(Note: it may be the case that 1. the acquisition function cannot raise
an exception for some reason, or 2. attempting to release a unacquired
resource is harmless, in which case it won't exactly hurt to put the
acquisition inside the try block. It might be true of mutexes for all
I know. But even in those rare cases, I recommend always sticking to
the idiom for consistency.)
Carl Banks
More information about the Python-list
mailing list