Read-Write lock class. A read-write lock differs from a standard threading.RLock() by allowing multiple threads to simultaneously hold a read lock, while allowing only a single thread to hold a write lock at the same point of time. When a read lock is requested while a write lock is
| 20 | # --------------- |
| 21 | |
| 22 | class ReadWriteLock(object): |
| 23 | """Read-Write lock class. A read-write lock differs from a standard |
| 24 | threading.RLock() by allowing multiple threads to simultaneously hold a |
| 25 | read lock, while allowing only a single thread to hold a write lock at the |
| 26 | same point of time. |
| 27 | |
| 28 | When a read lock is requested while a write lock is held, the reader |
| 29 | is blocked; when a write lock is requested while another write lock is |
| 30 | held or there are read locks, the writer is blocked. |
| 31 | |
| 32 | Writers are always preferred by this implementation: if there are blocked |
| 33 | threads waiting for a write lock, current readers may request more read |
| 34 | locks (which they eventually should free, as they starve the waiting |
| 35 | writers otherwise), but a new thread requesting a read lock will not |
| 36 | be granted one, and block. This might mean starvation for readers if |
| 37 | two writer threads interweave their calls to acquireWrite() without |
| 38 | leaving a window only for readers. |
| 39 | |
| 40 | In case a current reader requests a write lock, this can and will be |
| 41 | satisfied without giving up the read locks first, but, only one thread |
| 42 | may perform this kind of lock upgrade, as a deadlock would otherwise |
| 43 | occur. After the write lock has been granted, the thread will hold a |
| 44 | full write lock, and not be downgraded after the upgrading call to |
| 45 | acquireWrite() has been match by a corresponding release(). |
| 46 | """ |
| 47 | |
| 48 | def __init__(self): |
| 49 | """Initialize this read-write lock.""" |
| 50 | |
| 51 | # Condition variable, used to signal waiters of a change in object |
| 52 | # state. |
| 53 | self.__condition = Condition(Lock()) |
| 54 | |
| 55 | # Initialize with no writers. |
| 56 | self.__writer = None |
| 57 | self.__upgradewritercount = 0 |
| 58 | self.__pendingwriters = [] |
| 59 | |
| 60 | # Initialize with no readers. |
| 61 | self.__readers = {} |
| 62 | |
| 63 | def acquireRead(self, timeout=None): |
| 64 | """Acquire a read lock for the current thread, waiting at most |
| 65 | timeout seconds or doing a non-blocking check in case timeout is <= 0. |
| 66 | |
| 67 | In case timeout is None, the call to acquireRead blocks until the |
| 68 | lock request can be serviced. |
| 69 | |
| 70 | In case the timeout expires before the lock could be serviced, a |
| 71 | RuntimeError is thrown.""" |
| 72 | |
| 73 | if timeout is not None: |
| 74 | endtime = time() + timeout |
| 75 | me = currentThread() |
| 76 | self.__condition.acquire() |
| 77 | try: |
| 78 | if self.__writer is me: |
| 79 | # If we are the writer, grant a new read lock, always. |