harlowja / fasteners

A python package that provides useful locks.
Apache License 2.0
243 stars 45 forks source link

The documentation mentions rw_lock.acquire_read_lock() #106

Closed ArneBachmannDLR closed 9 months ago

ArneBachmannDLR commented 10 months ago

Hi I was writing a LockAdapter for threading.Lock around the acquire_read_lock() / acquire_write_lock() and release_read_lock() / .release_write_lock methods just to find out that they don' t exist in the code at all, contrary to what the README at PyPI says.

Is that API deprecated, an oversight in the docs or something not implemented yet? Would like to work with the rw_locks without a context manager.

psarka commented 10 months ago

Indeed, thanks for reporting this. I don't know how this discrepancy came to be, but I would like to add those four methods. I'll try to find time for this on Friday.

ArneBachmannDLR commented 10 months ago

No worries, that's good news! Just as a heads-up, maybe I'm doing everything wrong, but this is my idea:

class LockAdapter:  # adapt the fasteners API to the standard threading.Lock API
  def __init__(_, lock:ReaderWriterLock, write:bool = True) -> None: _.lock = lock; _.write = write
  def acquire(_, block:bool = True, timeout:Union[float,int] = -1) -> bool: return (_.lock.acquire_write_lock if _.write else _.lock.acquire_read_lock)()
  def release(_) -> None:                                                          (_.lock.release_write_lock if _.write else _.lock.release_read_lock)()
  def __enter__(_) -> 'LockAdapter':                                        return _.lock.__enter__()  # TODO: :Self
  def __exit__(_, exc_type, exc_val, exc_tb) -> bool:                       return _.lock.__exit()

Which doesn't work yet, so I did it like that:

class LockAdapter:
  def __init__(_, lock:ReaderWriterLock, write:bool = True) -> None:        _.cm = (lock.write_lock if write else lock.read_lock)()
  @functools.lru_cache(maxsize=None)  # ensure only called once per Lock
  def acquire(_, block:bool = True, timeout:Union[float,int] = -1) -> bool: _.cm.__enter__(); return True
  def release(_) -> None:                                                   _.cm.__exit__(None, None, None)
  def __enter__(_) -> 'ReaderWriterLock':                                   return _.cm.__enter__()  # TODO: :Self
  def __exit__(_, exc_type, exc_val, exc_tb) -> bool:                       return _.cm.__exit__(exc_type, exc_val, exc_tb)

Too weird? I just wanted a threading.Lock compatible interface for the ReadWriteLock, but likely I'm doing it all wrong.

psarka commented 10 months ago

I opened a PR with the methods, it would be awesome if you could review it (https://github.com/harlowja/fasteners/pull/108). If you don't feel comfortable or don't have time, then never mind, I'll let it sit a bit and then will take a look with fresh eyes.

What you doing makes sense, and in fact is very close to the API used by another library https://github.com/elarivie/pyReaderWriterLock. That other library has better inter-thread locks, so I would recommend to use that instead of fasteners :)

psarka commented 9 months ago

Done!

ArneBachmannDLR commented 9 months ago

Thanks so much! I greatly appreciate the update!