Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 只有一个底层锁的读写锁?_Python_Multithreading_Concurrency_Locking - Fatal编程技术网

Python 只有一个底层锁的读写锁?

Python 只有一个底层锁的读写锁?,python,multithreading,concurrency,locking,Python,Multithreading,Concurrency,Locking,我已经使用Python的并发原语(我想!)编写了一个读写锁。我在SO或其他地方读到的每个实现似乎都使用两个锁——一个用于读取,另一个用于写入。我的实现只包含一个用于读取的监视器,但我可能遗漏了一些关键的东西——有人能确认这会起作用吗?如果是这样,使用额外的写锁有什么好处 这是一个经典的读写锁,优先选择读卡器(可能会导致写卡器饥饿)。我使用虚拟缓存来演示读写操作 将线程导入为t 类读写缓存(对象): 定义初始化(自): self.cache={} self.reads=0 self.read_co

我已经使用Python的并发原语(我想!)编写了一个读写锁。我在SO或其他地方读到的每个实现似乎都使用两个锁——一个用于读取,另一个用于写入。我的实现只包含一个用于读取的监视器,但我可能遗漏了一些关键的东西——有人能确认这会起作用吗?如果是这样,使用额外的写锁有什么好处

这是一个经典的读写锁,优先选择读卡器(可能会导致写卡器饥饿)。我使用虚拟缓存来演示读写操作

将线程导入为t
类读写缓存(对象):
定义初始化(自):
self.cache={}
self.reads=0
self.read_cond=t.Condition(t.Lock())
def读取(自身,钥匙):
使用self.read_cond:#注册读取,以便写入将等待()
self.reads+=1
结果=self.cache[键]
使用self.read_cond:
self.reads-=1
如果不是self.reads:
self.read\u cond.notify\u all()
返回结果
def更新(自身、密钥、值):
使用self.read_cond:
而self.com阅读:
self.read_cond.wait()#等待读取清除
self.cache[key]=值#带读锁,更新值

您没有使用单个锁
您正在使用一个锁和一个条件变量

self.read_lock = t.Condition(t.Lock())
条件变量也是并发原语。比锁更复杂的锁

注意:请不要调用条件变量对象
read\u lock

编辑: 您的代码在我看来似乎是正确的,因为它解决了问题。正如你所说,这可能会使作家挨饿。这不是一个小问题。读写器背后的逻辑是读可能比写多得多

一个额外的锁允许解决第二个读写器问题,在这个问题上写写器不会饿死。实际上,当有写入程序在等待资源时,读者必须等待。

还有一个使用锁和条件的解决方案。处理饥饿问题,还支持从同一线程请求时将读锁提升为写锁

# From O'Reilly Python Cookbook by David Ascher, Alex Martelli
# With changes to cover the starvation situation where a continuous
#   stream of readers may starve a writer, Lock Promotion and Context Managers

class ReadWriteLock:
  """ A lock object that allows many simultaneous "read locks", but
  only one "write lock." """

  def __init__(self, withPromotion=False):
    self._read_ready = threading.Condition(threading.RLock(  ))
    self._readers = 0
    self._writers = 0
    self._promote = withPromotion
    self._readerList = []  # List of Reader thread IDs
    self._writerList = []  # List of Writer thread IDs

  def acquire_read(self):
    logging.debug("RWL : acquire_read()")
    """ Acquire a read lock. Blocks only if a thread has
    acquired the write lock. """
    self._read_ready.acquire(  )
    try:
      while self._writers > 0:
        self._read_ready.wait()
      self._readers += 1
    finally:
      self._readerList.append(threading.get_ident())
      self._read_ready.release(  )

  def release_read(self):
    logging.debug("RWL : release_read()")
    """ Release a read lock. """
    self._read_ready.acquire(  )
    try:
      self._readers -= 1
      if not self._readers:
        self._read_ready.notifyAll(  )
    finally:
      self._readerList.remove(threading.get_ident())
      self._read_ready.release(  )

  def acquire_write(self):
    logging.debug("RWL : acquire_write()")
    """ Acquire a write lock. Blocks until there are no
    acquired read or write locks. """
    self._read_ready.acquire(  )   # A re-entrant lock lets a thread re-acquire the lock
    self._writers += 1
    self._writerList.append(threading.get_ident())
    while self._readers > 0:
      # promote to write lock, only if all the readers are trying to promote to writer
      # If there are other reader threads, then wait till they complete reading
      if self._promote and threading.get_ident() in self._readerList and set(self._readerList).issubset(set(self._writerList)):
        break
      else:
        self._read_ready.wait(  )

  def release_write(self):
    logging.debug("RWL : release_write()")
    """ Release a write lock. """
    self._writers -= 1
    self._writerList.remove(threading.get_ident())
    self._read_ready.notifyAll(  )
    self._read_ready.release(  )

#----------------------------------------------------------------------------------------------------------

class ReadRWLock:
  # Context Manager class for ReadWriteLock
  def __init__(self, rwLock):
    self.rwLock = rwLock

  def __enter__(self):
    self.rwLock.acquire_read()
    return self         # Not mandatory, but returning to be safe

  def __exit__(self, exc_type, exc_value, traceback):
    self.rwLock.release_read()
    return False        # Raise the exception, if exited due to an exception

#----------------------------------------------------------------------------------------------------------

class WriteRWLock:
  # Context Manager class for ReadWriteLock
  def __init__(self, rwLock):
    self.rwLock = rwLock

  def __enter__(self):
    self.rwLock.acquire_write()
    return self         # Not mandatory, but returning to be safe

  def __exit__(self, exc_type, exc_value, traceback):
    self.rwLock.release_write()
    return False        # Raise the exception, if exited due to an exception

#----------------------------------------------------------------------------------------------------------

在哪里可以找到双锁版本的示例?@ErikR,您可以在这里找到一些示例:@ErikR,太早按回车键。见下面的问题。接受答案中的每个链接,以及pasztorpisti的答案和代码。它们要么使用两个锁,要么有某种双事件系统,在这种系统中,写入程序和读取程序在完成时都会相互发出信号。啊,是的,这很有道理——我想我实际上是在使用锁和事件。我已经重新命名了这个对象,想重新讨论一下它的正确性吗?