如何在Python 2.7中实现具有超时的锁定

Nik*_* B. 22 python multithreading synchronization

有没有办法在Python中为多线程目的实现锁定,其acquire方法可以有任意超时?到目前为止,我发现的唯一可行的解​​决方案是使用轮询

  • 我发现不优雅和低效
  • 不保留锁的有限等待/进度保证作为临界区问题的解决方案

有没有更好的方法来实现这个?

Sin*_*ion 21

详细阐述史蒂文的评论建议:

import threading
import time

lock = threading.Lock()
cond = threading.Condition(threading.Lock())

def waitLock(timeout):
    with cond:
        current_time = start_time = time.time()
        while current_time < start_time + timeout:
            if lock.acquire(False):
                return True
            else:
                cond.wait(timeout - current_time + start_time)
                current_time = time.time()
    return False
Run Code Online (Sandbox Code Playgroud)

需要注意的事项:

  • 有两个threading.Lock()对象,一个是内部的threading.Condition().
  • 在操纵时cond,获得锁定; 该wait()操作进行解锁,虽然如此,任意数量的线程可以看它.
  • 等待嵌入在跟踪时间的for循环中. threading.Condition可以通过超时以外的原因获得通知,因此您仍需要跟踪时间,如果您确实希望它过期.
  • 即使有条件,你仍然"轮询"真正的锁,因为它可能有多个线程被唤醒并争夺锁.如果lock.acquire失败,循环返回等待.
  • waitLock函数的调用者应该跟a一个lock.release()a,cond.notify()以便等待它的其他线程被通知他们应该重试获取锁.这未在示例中显示.

  • 你可以把它全部包装在一个类中来实现一个`TimeoutLock`,所以你不要依赖正确使用lock和condition变量的调用者.虽然在使用条件变量(使用锁实现)来实现锁定时,我有点开心.:) (2认同)

Hav*_*vok 5

我的版本使用线程安全队列http://docs.python.org/2/library/queue.html及其支持超时的put/get方法.

到目前为止工作正常,但如果有人可以对其进行同行评审,我将不胜感激.

"""
Thread-safe lock mechanism with timeout support module.
"""

from threading import ThreadError, current_thread
from Queue import Queue, Full, Empty


class TimeoutLock(object):
    """
    Thread-safe lock mechanism with timeout support.
    """

    def __init__(self, mutex=True):
        """
        Constructor.
        Mutex parameter specifies if the lock should behave like a Mutex, and
        thus use the concept of thread ownership.
        """
        self._queue = Queue(maxsize=1)
        self._owner = None
        self._mutex = mutex

    def acquire(self, timeout=0):
        """
        Acquire the lock.
        Returns True if the lock was succesfully acquired, False otherwise.

        Timeout:
        - < 0 : Wait forever.
        -   0 : No wait.
        - > 0 : Wait x seconds.
        """
        th = current_thread()
        try:
            self._queue.put(
                th, block=(timeout != 0),
                timeout=(None if timeout < 0 else timeout)
            )
        except Full:
            return False

        self._owner = th
        return True

    def release(self):
        """
        Release the lock.
        If the lock is configured as a Mutex, only the owner thread can release
        the lock. If another thread attempts to release the lock a
        ThreadException is raised.
        """
        th = current_thread()
        if self._mutex and th != self._owner:
            raise ThreadError('This lock isn\'t owned by this thread.')

        self._owner = None
        try:
            self._queue.get(False)
            return True
        except Empty:
            raise ThreadError('This lock was released already.')
Run Code Online (Sandbox Code Playgroud)

  • 解决方案似乎是正确的,但 Python 队列是用两个 Condition 对象实现的(参见 https://github.com/python/cpython/blob/master/Lib/queue.py)所以 @SingleNegationElimination 答案(https://stackoverflow. com/a/8393033/1763149)稍微好一点。 (2认同)