2005-09-26 04:01:35 +08:00
|
|
|
"""
|
|
|
|
Synchronization primitives:
|
2007-04-25 15:25:22 +08:00
|
|
|
|
2005-09-26 04:01:35 +08:00
|
|
|
- reader-writer lock (preference to writers)
|
|
|
|
|
|
|
|
(Contributed to Django by eugene@lazutkin.com)
|
|
|
|
"""
|
|
|
|
|
2011-11-27 12:28:31 +08:00
|
|
|
import contextlib
|
2015-01-28 22:55:52 +08:00
|
|
|
import threading
|
2005-09-26 04:01:35 +08:00
|
|
|
|
2011-11-27 12:28:31 +08:00
|
|
|
|
2017-01-19 15:39:46 +08:00
|
|
|
class RWLock:
|
2005-09-26 04:01:35 +08:00
|
|
|
"""
|
|
|
|
Classic implementation of reader-writer lock with preference to writers.
|
2007-04-25 15:25:22 +08:00
|
|
|
|
2005-09-26 04:01:35 +08:00
|
|
|
Readers can access a resource simultaneously.
|
|
|
|
Writers get an exclusive access.
|
2007-04-25 15:25:22 +08:00
|
|
|
|
2005-09-26 04:01:35 +08:00
|
|
|
API is self-descriptive:
|
|
|
|
reader_enters()
|
|
|
|
reader_leaves()
|
|
|
|
writer_enters()
|
|
|
|
writer_leaves()
|
|
|
|
"""
|
|
|
|
def __init__(self):
|
2013-10-22 21:31:43 +08:00
|
|
|
self.mutex = threading.RLock()
|
|
|
|
self.can_read = threading.Semaphore(0)
|
2005-09-26 04:01:35 +08:00
|
|
|
self.can_write = threading.Semaphore(0)
|
2013-10-22 21:31:43 +08:00
|
|
|
self.active_readers = 0
|
|
|
|
self.active_writers = 0
|
2005-09-26 04:01:35 +08:00
|
|
|
self.waiting_readers = 0
|
|
|
|
self.waiting_writers = 0
|
2007-04-25 15:25:22 +08:00
|
|
|
|
2005-09-26 04:01:35 +08:00
|
|
|
def reader_enters(self):
|
2011-11-27 12:28:31 +08:00
|
|
|
with self.mutex:
|
2005-09-26 04:01:35 +08:00
|
|
|
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()
|
2007-04-25 15:25:22 +08:00
|
|
|
|
2005-09-26 04:01:35 +08:00
|
|
|
def reader_leaves(self):
|
2011-11-27 12:28:31 +08:00
|
|
|
with self.mutex:
|
2005-09-26 04:01:35 +08:00
|
|
|
self.active_readers -= 1
|
|
|
|
if self.active_readers == 0 and self.waiting_writers != 0:
|
2013-10-22 21:31:43 +08:00
|
|
|
self.active_writers += 1
|
2005-09-26 04:01:35 +08:00
|
|
|
self.waiting_writers -= 1
|
|
|
|
self.can_write.release()
|
2011-11-27 12:28:31 +08:00
|
|
|
|
|
|
|
@contextlib.contextmanager
|
|
|
|
def reader(self):
|
|
|
|
self.reader_enters()
|
|
|
|
try:
|
|
|
|
yield
|
2005-09-26 04:01:35 +08:00
|
|
|
finally:
|
2011-11-27 12:28:31 +08:00
|
|
|
self.reader_leaves()
|
2007-04-25 15:25:22 +08:00
|
|
|
|
2005-09-26 04:01:35 +08:00
|
|
|
def writer_enters(self):
|
2011-11-27 12:28:31 +08:00
|
|
|
with self.mutex:
|
2005-09-26 04:01:35 +08:00
|
|
|
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()
|
2007-04-25 15:25:22 +08:00
|
|
|
|
2005-09-26 04:01:35 +08:00
|
|
|
def writer_leaves(self):
|
2011-11-27 12:28:31 +08:00
|
|
|
with self.mutex:
|
2005-09-26 04:01:35 +08:00
|
|
|
self.active_writers -= 1
|
|
|
|
if self.waiting_writers != 0:
|
2013-10-22 21:31:43 +08:00
|
|
|
self.active_writers += 1
|
2005-09-26 04:01:35 +08:00
|
|
|
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
|
2011-11-27 12:28:31 +08:00
|
|
|
|
|
|
|
@contextlib.contextmanager
|
|
|
|
def writer(self):
|
|
|
|
self.writer_enters()
|
|
|
|
try:
|
|
|
|
yield
|
2005-09-26 04:01:35 +08:00
|
|
|
finally:
|
2012-03-30 16:02:08 +08:00
|
|
|
self.writer_leaves()
|