On Sun, 25 Sep 2005 23:30:21 -0400, Victor Ng <[EMAIL PROTECTED]> wrote:
>You could do it with a metaclass, but I think that's probably overkill.
>
>It's not really efficient as it's doing test/set of an RLock all the
>time, but hey - you didn't ask for efficient.  :)

There's a race condition in this version of synchronized which can allow two or 
more threads to execute the synchronized function simultaneously.

>
>      1 import threading
>      2
>      3 def synchronized(func):
>      4     def innerMethod(self, *args, **kwargs):
>      5         if not hasattr(self, '_sync_lock'):

Imagine two threads reach the above test at the same time - they both discover 
there is no RLock protecting this function.  They both entire this suite to 
create one.

>      6             self._sync_lock = threading.RLock()

Now one of them zooms ahead, creating the RLock and acquiring it on the next 
line.  The other one finally manages to get some runtime again afterwards and 
creates another RLock, clobbering the first.

>      7         self._sync_lock.acquire()

Now it proceeds to this point and acquires the newly created RLock.  Woops.  
Two threads now think they are allowed to run this function.

>      8         print 'acquired %r' % self._sync_lock
>      9         try:
>     10             return func(self, *args, **kwargs)

And so they do.

>     11         finally:
>     12             self._sync_lock.release()
>     13             print 'released %r' % self._sync_lock

Of course, when the second gets to the finally suite, it will explode, since it 
will be releasing the same lock the first thread to get here has already 
released.

>     14     return innerMethod
>     15
>     16 class Foo(object):
>     17     @synchronized
>     18     def mySyncMethod(self):
>     19         print "blah"
>     20
>     21
>     22 f = Foo()
>     23 f.mySyncMethod()

To avoid this race condition, you need to serialize lock creation.  This is 
exactly what Twisted's implementation does.  You can read that version at 
<http://svn.twistedmatrix.com/cvs/trunk/twisted/python/threadable.py?view=markup&rev=13745>.
The code is factored somewhat differently: the functionality is presented as 
pre- and post-execution hooks, and there is function decorator.  The concept is 
the same, however.

Jp
-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to