Metaclasses, decorators, and synchronization

Victor Ng crankycoder at gmail.com
Mon Sep 26 01:27:56 EDT 2005


Hmmm.... well that's obvious enough. This is why I shouldn't write code off
the cuff on c.l.p.... :)

OTOH - if I just assign the RLock in the base classes initializer, is there
any problem?

vic

On 9/26/05, Jp Calderone <exarkun at divmod.com> wrote:
>
> On Sun, 25 Sep 2005 23:30:21 -0400, Victor Ng <crankycoder at gmail.com>
> 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
>



--
"Never attribute to malice that which can be adequately explained by
stupidity." - Hanlon's Razor
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20050926/a826ef65/attachment.html>


More information about the Python-list mailing list