Skip to content

Commit

Permalink
sync: allow specifying identity of reader when using RWLock
Browse files Browse the repository at this point in the history
  • Loading branch information
koreno committed Jun 22, 2020
1 parent c3850ec commit e8242bd
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 7 deletions.
34 changes: 28 additions & 6 deletions easypy/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ def __init__(self, name=None):
self._lease_timer = None

def __repr__(self):
owners = ", ".join(map(str, sorted(self.owners.keys())))
owners = ", ".join(sorted(map(str, self.owners.keys())))
lease_timer = self._lease_timer # touch once to avoid races
if lease_timer:
mode = "exclusively ({})".format(lease_timer.elapsed)
Expand All @@ -700,25 +700,47 @@ def __call__(self):
return self

def __enter__(self):
self.acquire()
return self

def acquire(self, identifier=None):
"""
Acquire the lock as a reader.
Optionally specify the identity of the reader (defaults to thready identity).
"""
while not self.cond.acquire(timeout=15):
_logger.debug("%s - waiting...", self)

if not identifier:
identifier = _get_my_ident()

try:
self.owners[_get_my_ident()] += 1
self.owners[identifier] += 1
_verbose_logger.debug("%s - acquired (non-exclusively)", self)
return self
finally:
self.cond.release()

def __exit__(self, *args):
self.release()

def release(self, identifier=None):
"""
Release the lock as a reader.
Optionally specify the identity of the reader (defaults to thready identity).
"""

while not self.cond.acquire(timeout=15):
_logger.debug("%s - waiting...", self)

if not identifier:
identifier = _get_my_ident()
try:
my_ident = _get_my_ident()
self.owners[my_ident] -= 1
if not self.owners[my_ident]:
self.owners.pop(my_ident) # don't inflate the soft lock keys with threads that does not own it
if not self.owners[identifier]:
raise RuntimeError("cannot release un-acquired lock")
self.owners[identifier] -= 1
if not self.owners[identifier]:
self.owners.pop(identifier)
self.cond.notify()
_verbose_logger.debug("%s - released (non-exclusive)", self)
finally:
Expand Down
28 changes: 27 additions & 1 deletion tests/test_rwlock.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import threading

import pytest
import logging
from easypy.concurrency import concurrent
from easypy.sync import RWLock
Expand Down Expand Up @@ -76,3 +76,29 @@ def write():
main_ctrl.clear()
logging.info("write lock released")
assert not state.reading and not state.writing


def test_rwlock_different_threads():
lock = RWLock("test")
e = threading.Event()

def a(id=None):
lock.acquire(id)
e.wait()

def b(id=None):
lock.release(id)
e.set()

with concurrent(a):
assert lock.owners
with pytest.raises(RuntimeError):
b()
e.set()
assert lock.owners

with concurrent(a, "same"):
assert lock.owners
with concurrent(b, "same"):
pass
assert lock.owners

0 comments on commit e8242bd

Please sign in to comment.