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