Source code for rwlock.imp_1.imp
"""
Module **rwlock.imp_1.imp** has class ``Imp`` that implements
the read-write-lock service.
To instantiate and drive ``Imp`` from **rwlock/user.py**, in the parent
directory run "``python user.py <num_threads> <num_ops> imp_1.imp <mri>``".
Or instantiate ``Imp`` in your own program and drive it from there.
"""
from threading import Lock, Condition
import argparse, sys
[docs]class Imp:
"""
An implementation of the read-write-lock service. Ensures writers do
not starve by limiting a "read interval" to at most *mri* reads,
where *mri* is an initialization argument. (A "read" interval starts
when ``nr`` becomes non-zero and ends when ``nr`` becomes zero.)
Imp has functions ``acqw()``, ``relr()``, ``acqw()`` and ``relw()``.
It maintains the following variables:
- ``mri`` (constant int): max number of reads in a "read" interval;
set to ``__init__`` parameter ``mri``.
- ``nr`` (int): number of threads holding a read lock; initially 0.
- ``nw`` (int): number of threads holding a write lock; initially 0.
- ``nx`` (int): number of reads started in current interval; initially 0.
- ``lck`` (lock): protects ``nr`` and ``nw``.
- ``cvr`` (condition): to wait for ``nw == 0`` and ``nx < max_nx``
- ``cvw`` (condition): to wait for ``nr`` and ``nw`` equal to 0.
When a thread executes ``acqw()``, it waits on ``cvw`` until ``nr`` and
``nw`` are both 0, then increments ``nw`` and returns.
At this point, no thread can acquire a write lock or a read lock.
When a thread executes ``relw()``, it decrements ``nw`` and returns.
When a thread executes ``acqr()``, it waits on ``cvr`` until ``nw == 0``
and ``nx < mri`` hold, then increments ``nr`` and ``nx``, and returns.
At this point a thread cannot get a write lock, and can get a read lock
only if ``nx < mri`` holds.
When a thread executes ``relr()``, it decrements ``nr`` and, if ``nr``
has become zero, zeros ``nx``.
"""
def __init__(self, argv):
p = argparse.ArgumentParser()
p.add_argument('mri', type=int,
help='max number of reads in a read interval')
args = p.parse_args(argv[1:])
self.mri = args.mri
self.nr = 0
self.nw = 0
self.nx = 0
self.lck = Lock()
self.cvr = Condition(self.lck)
self.cvw = Condition(self.lck)
def acqr(self):
with self.cvr:
while self.nw > 0 or self.nx == self.mri:
self.cvr.wait()
self.nr += 1
self.nx += 1
def relr(self):
with self.lck:
self.nr -= 1
if self.nr == 0:
self.nx = 0
self.cvw.notify()
self.cvr.notify_all()
def acqw(self):
with self.cvw:
while self.nr + self.nw > 0:
self.cvw.wait()
self.nw += 1
def relw(self):
with self.lck:
self.nw -= 1
self.cvr.notify_all()
self.cvw.notify()
##### end class Imp #############################
if __name__ == '__main__':
imp = Imp(sys.argv)