|  | """ | 
|  | Synchronization primitives: | 
|  |  | 
|  | - reader-writer lock (preference to writers) | 
|  |  | 
|  | (Contributed to Django by eugene@lazutkin.com) | 
|  | """ | 
|  |  | 
|  | import contextlib | 
|  | try: | 
|  | import threading | 
|  | except ImportError: | 
|  | import dummy_threading as threading | 
|  |  | 
|  |  | 
|  | class RWLock(object): | 
|  | """ | 
|  | Classic implementation of reader-writer lock with preference to writers. | 
|  |  | 
|  | Readers can access a resource simultaneously. | 
|  | Writers get an exclusive access. | 
|  |  | 
|  | API is self-descriptive: | 
|  | reader_enters() | 
|  | reader_leaves() | 
|  | writer_enters() | 
|  | writer_leaves() | 
|  | """ | 
|  | def __init__(self): | 
|  | self.mutex     = threading.RLock() | 
|  | self.can_read  = threading.Semaphore(0) | 
|  | self.can_write = threading.Semaphore(0) | 
|  | self.active_readers  = 0 | 
|  | self.active_writers  = 0 | 
|  | self.waiting_readers = 0 | 
|  | self.waiting_writers = 0 | 
|  |  | 
|  | def reader_enters(self): | 
|  | with self.mutex: | 
|  | if self.active_writers == 0 and self.waiting_writers == 0: | 
|  | self.active_readers += 1 | 
|  | self.can_read.release() | 
|  | else: | 
|  | self.waiting_readers += 1 | 
|  | self.can_read.acquire() | 
|  |  | 
|  | def reader_leaves(self): | 
|  | with self.mutex: | 
|  | self.active_readers -= 1 | 
|  | if self.active_readers == 0 and self.waiting_writers != 0: | 
|  | self.active_writers  += 1 | 
|  | self.waiting_writers -= 1 | 
|  | self.can_write.release() | 
|  |  | 
|  | @contextlib.contextmanager | 
|  | def reader(self): | 
|  | self.reader_enters() | 
|  | try: | 
|  | yield | 
|  | finally: | 
|  | self.reader_leaves() | 
|  |  | 
|  | def writer_enters(self): | 
|  | with self.mutex: | 
|  | if self.active_writers == 0 and self.waiting_writers == 0 and self.active_readers == 0: | 
|  | self.active_writers += 1 | 
|  | self.can_write.release() | 
|  | else: | 
|  | self.waiting_writers += 1 | 
|  | self.can_write.acquire() | 
|  |  | 
|  | def writer_leaves(self): | 
|  | with self.mutex: | 
|  | self.active_writers -= 1 | 
|  | if self.waiting_writers != 0: | 
|  | self.active_writers  += 1 | 
|  | self.waiting_writers -= 1 | 
|  | self.can_write.release() | 
|  | elif self.waiting_readers != 0: | 
|  | t = self.waiting_readers | 
|  | self.waiting_readers = 0 | 
|  | self.active_readers += t | 
|  | while t > 0: | 
|  | self.can_read.release() | 
|  | t -= 1 | 
|  |  | 
|  | @contextlib.contextmanager | 
|  | def writer(self): | 
|  | self.writer_enters() | 
|  | try: | 
|  | yield | 
|  | finally: | 
|  | self.writer_leaves() |