symbian-qemu-0.9.1-12/python-2.6.1/Demo/metaclasses/Synch.py
changeset 1 2fb8b9db1c86
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symbian-qemu-0.9.1-12/python-2.6.1/Demo/metaclasses/Synch.py	Fri Jul 31 15:01:17 2009 +0100
@@ -0,0 +1,256 @@
+"""Synchronization metaclass.
+
+This metaclass  makes it possible to declare synchronized methods.
+
+"""
+
+import thread
+
+# First we need to define a reentrant lock.
+# This is generally useful and should probably be in a standard Python
+# library module.  For now, we in-line it.
+
+class Lock:
+
+    """Reentrant lock.
+
+    This is a mutex-like object which can be acquired by the same
+    thread more than once.  It keeps a reference count of the number
+    of times it has been acquired by the same thread.  Each acquire()
+    call must be matched by a release() call and only the last
+    release() call actually releases the lock for acquisition by
+    another thread.
+
+    The implementation uses two locks internally:
+
+    __mutex is a short term lock used to protect the instance variables
+    __wait is the lock for which other threads wait
+
+    A thread intending to acquire both locks should acquire __wait
+    first.
+
+   The implementation uses two other instance variables, protected by
+   locking __mutex:
+
+    __tid is the thread ID of the thread that currently has the lock
+    __count is the number of times the current thread has acquired it
+
+    When the lock is released, __tid is None and __count is zero.
+
+    """
+
+    def __init__(self):
+        """Constructor.  Initialize all instance variables."""
+        self.__mutex = thread.allocate_lock()
+        self.__wait = thread.allocate_lock()
+        self.__tid = None
+        self.__count = 0
+
+    def acquire(self, flag=1):
+        """Acquire the lock.
+
+        If the optional flag argument is false, returns immediately
+        when it cannot acquire the __wait lock without blocking (it
+        may still block for a little while in order to acquire the
+        __mutex lock).
+
+        The return value is only relevant when the flag argument is
+        false; it is 1 if the lock is acquired, 0 if not.
+
+        """
+        self.__mutex.acquire()
+        try:
+            if self.__tid == thread.get_ident():
+                self.__count = self.__count + 1
+                return 1
+        finally:
+            self.__mutex.release()
+        locked = self.__wait.acquire(flag)
+        if not flag and not locked:
+            return 0
+        try:
+            self.__mutex.acquire()
+            assert self.__tid == None
+            assert self.__count == 0
+            self.__tid = thread.get_ident()
+            self.__count = 1
+            return 1
+        finally:
+            self.__mutex.release()
+
+    def release(self):
+        """Release the lock.
+
+        If this thread doesn't currently have the lock, an assertion
+        error is raised.
+
+        Only allow another thread to acquire the lock when the count
+        reaches zero after decrementing it.
+
+        """
+        self.__mutex.acquire()
+        try:
+            assert self.__tid == thread.get_ident()
+            assert self.__count > 0
+            self.__count = self.__count - 1
+            if self.__count == 0:
+                self.__tid = None
+                self.__wait.release()
+        finally:
+            self.__mutex.release()
+
+
+def _testLock():
+
+    done = []
+
+    def f2(lock, done=done):
+        lock.acquire()
+        print "f2 running in thread %d\n" % thread.get_ident(),
+        lock.release()
+        done.append(1)
+
+    def f1(lock, f2=f2, done=done):
+        lock.acquire()
+        print "f1 running in thread %d\n" % thread.get_ident(),
+        try:
+            f2(lock)
+        finally:
+            lock.release()
+        done.append(1)
+
+    lock = Lock()
+    lock.acquire()
+    f1(lock)                            # Adds 2 to done
+    lock.release()
+
+    lock.acquire()
+
+    thread.start_new_thread(f1, (lock,)) # Adds 2
+    thread.start_new_thread(f1, (lock, f1)) # Adds 3
+    thread.start_new_thread(f2, (lock,)) # Adds 1
+    thread.start_new_thread(f2, (lock,)) # Adds 1
+
+    lock.release()
+    import time
+    while len(done) < 9:
+        print len(done)
+        time.sleep(0.001)
+    print len(done)
+
+
+# Now, the Locking metaclass is a piece of cake.
+# As an example feature, methods whose name begins with exactly one
+# underscore are not synchronized.
+
+from Meta import MetaClass, MetaHelper, MetaMethodWrapper
+
+class LockingMethodWrapper(MetaMethodWrapper):
+    def __call__(self, *args, **kw):
+        if self.__name__[:1] == '_' and self.__name__[1:] != '_':
+            return apply(self.func, (self.inst,) + args, kw)
+        self.inst.__lock__.acquire()
+        try:
+            return apply(self.func, (self.inst,) + args, kw)
+        finally:
+            self.inst.__lock__.release()
+
+class LockingHelper(MetaHelper):
+    __methodwrapper__ = LockingMethodWrapper
+    def __helperinit__(self, formalclass):
+        MetaHelper.__helperinit__(self, formalclass)
+        self.__lock__ = Lock()
+
+class LockingMetaClass(MetaClass):
+    __helper__ = LockingHelper
+
+Locking = LockingMetaClass('Locking', (), {})
+
+def _test():
+    # For kicks, take away the Locking base class and see it die
+    class Buffer(Locking):
+        def __init__(self, initialsize):
+            assert initialsize > 0
+            self.size = initialsize
+            self.buffer = [None]*self.size
+            self.first = self.last = 0
+        def put(self, item):
+            # Do we need to grow the buffer?
+            if (self.last+1) % self.size != self.first:
+                # Insert the new item
+                self.buffer[self.last] = item
+                self.last = (self.last+1) % self.size
+                return
+            # Double the buffer size
+            # First normalize it so that first==0 and last==size-1
+            print "buffer =", self.buffer
+            print "first = %d, last = %d, size = %d" % (
+                self.first, self.last, self.size)
+            if self.first <= self.last:
+                temp = self.buffer[self.first:self.last]
+            else:
+                temp = self.buffer[self.first:] + self.buffer[:self.last]
+            print "temp =", temp
+            self.buffer = temp + [None]*(self.size+1)
+            self.first = 0
+            self.last = self.size-1
+            self.size = self.size*2
+            print "Buffer size doubled to", self.size
+            print "new buffer =", self.buffer
+            print "first = %d, last = %d, size = %d" % (
+                self.first, self.last, self.size)
+            self.put(item)              # Recursive call to test the locking
+        def get(self):
+            # Is the buffer empty?
+            if self.first == self.last:
+                raise EOFError          # Avoid defining a new exception
+            item = self.buffer[self.first]
+            self.first = (self.first+1) % self.size
+            return item
+
+    def producer(buffer, wait, n=1000):
+        import time
+        i = 0
+        while i < n:
+            print "put", i
+            buffer.put(i)
+            i = i+1
+        print "Producer: done producing", n, "items"
+        wait.release()
+
+    def consumer(buffer, wait, n=1000):
+        import time
+        i = 0
+        tout = 0.001
+        while i < n:
+            try:
+                x = buffer.get()
+                if x != i:
+                    raise AssertionError, \
+                          "get() returned %s, expected %s" % (x, i)
+                print "got", i
+                i = i+1
+                tout = 0.001
+            except EOFError:
+                time.sleep(tout)
+                tout = tout*2
+        print "Consumer: done consuming", n, "items"
+        wait.release()
+
+    pwait = thread.allocate_lock()
+    pwait.acquire()
+    cwait = thread.allocate_lock()
+    cwait.acquire()
+    buffer = Buffer(1)
+    n = 1000
+    thread.start_new_thread(consumer, (buffer, cwait, n))
+    thread.start_new_thread(producer, (buffer, pwait, n))
+    pwait.acquire()
+    print "Producer done"
+    cwait.acquire()
+    print "All done"
+    print "buffer size ==", len(buffer.buffer)
+
+if __name__ == '__main__':
+    _testLock()
+    _test()