<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">from threading import Lock, Condition

class ReaderWriterMonitor(object):

  def __init__(self):
    self.lock = Lock()

    self.num_readers = 0
    self.is_writer   = False

    # predicate: not self.is_writer
    self.no_writers = Condition(self.lock)

    # predicate: self.num_readers == 0 and not self.is_writer
    # NOTE: safe to call notify, waiter must invalidate
    self.no_rw = Condition(self.lock)

  def enter_reader(self):
    with self.lock:
      while not (not self.is_writer):
        self.no_writers.wait()

      self.num_readers += 1
      # no need to notify

  def enter_writer(self):
    with self.lock:
      while not (self.num_readers == 0 and not self.is_writer):
        self.no_rw.wait()

      self.is_writer = True
      # no need to notify

  def leave_reader(self):
    with self.lock:
      self.num_readers -= 1

      if self.num_readers == 0:
        self.no_rw.notify()

  def leave_writer(self):
    with self.lock:
      self.is_writer = False
      # note: no_rw must not have been true before because of precondition
      # note: no_rw guaranteed because invariant says readers == 0
      # note: notify is safe because no_rw guaranteed to be invalidated
      self.no_rw.notify()
      self.no_writers.notifyAll()

</pre></body></html>