Automatic access serialization

From: Gabriel Genellina (gagenellina_at_softlab.com.ar)
Date: 01/31/04


Date: 30 Jan 2004 17:53:44 -0800

Hello!

I have a number of objects that are not thread-safe - no locking
mechanism was originally provided.
But I want to use them in a thread-safe way. I don't want to analyze
each class details, looking for where and when I must protect the
code. So I wrote this sort-of-brute-force locking mechanism using
threading.RLock() around __getattr__ / __setattr__ / __delattr__.
The idea is that *any* attribute and method access is protected by the
lock. The calling thread may acquire the lock multiple times, but
other threads must wait until it is released.
This may be too much restrictive, and a bottleneck in performance,
since *all* accesses are effectively serialized - but it's the best I
could imagine without deeply analyzing the actual code.
I *think* this works well, but since I'm not an expert in these
things, any comments are welcome. Specially what could go wrong, if
someone could anticipate it.
Note: As written, this only works for old-style classes. I think that
just by adding a similar __getattribute__ would suffice for new-style
classes too - is that true?

--- begin autolock.py ---
import threading

class AutoLock:
    # "brute-force" locking wrapper to any object
    # *all* attribute access is serialized in a thread-safe way.
    
    def __init__(self, target):
        dict = self.__dict__
        dict['_%s__lock'%self.__class__.__name__] = threading.RLock()
        dict['_%s__target'%self.__class__.__name__] = target

    def __getattr__(self, key):
        self.__lock.acquire()
        try:
            return getattr(self.__target, key)
        finally:
            self.__lock.release()
            
    def __setattr__(self, key, value):
        self.__lock.acquire()
        try:
            setattr(self.__target, key, value)
        finally:
            self.__lock.release()
            
    def __delattr__(self, key):
        self.__lock.acquire()
        try:
            delattr(self.__target, key)
        finally:
            self.__lock.release()

--- end autolock.py ---

Gabriel Genellina
Softlab SRL



Relevant Pages

  • Re: file offset corruption on 32-bit machines?
    ... I can easily imagine such a program. ... The easiest way to imagine a program not doing locking and being useful ... anyway (as long as the kernel is thread-safe) is to use the same arguments ... But he notices that the corruption isn't consistent with that hypothesis. ...
    (Linux-Kernel)
  • Re: locking
    ... > thread-safe is probably a much bigger task. ... I saw that the routing code seems to use macros for the locking ... Do you use macros everywhere? ... Regarding synchronization -- semaphores can be used to implement mutual ...
    (freebsd-net)
  • Re: Concurrency and delegates
    ... thread-safe, people do actually do _something_ like this. ... One technique I've seen suggested doesn't use locking at all. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Concurrency and delegates
    ... Is there some reason I'm not ... I'm not really clear on why that's considered thread-safe, but it's apparently common enough that the question of the assignment to a local variable being optimized out has come up before. ... Unfortunately, I don't recall any thread that ever provided any conclusive statements one way or the other on either issue (whether the technique works, and whether it can be accidently defeated by the optimizer). ... The only discrepancy would be the use of "this" as opposed to a dedicated object instance for locking. ...
    (microsoft.public.dotnet.languages.csharp)