首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >fcntl.flock -如何实现超时?

fcntl.flock -如何实现超时?
EN

Stack Overflow用户
提问于 2011-03-10 11:45:06
回答 5查看 9.6K关注 0票数 12

我使用的是python 2.7

我想在fcntl.flock()周围创建一个包装器函数,它将在设置的时间间隔后超时:

代码语言:javascript
复制
wrapper_function(timeout):

我尝试在另一个线程上调用并使用thread.join(超时),但fcntl.flock()似乎继续阻塞:

代码语言:javascript
复制
def GetLock(self, timeout):
    """Returns true if lock is aquired, false if lock is already in use"""
    self.__lock_file = open('proc_lock', 'w')

    def GetLockOrTimeOut():
        print 'ProcessLock: Acquiring Lock'            
        fcntl.flock(self.__lock_file.fileno(), fcntl.LOCK_EX)
        print 'ProcessLock: Lock Acquired'

    thread = threading.Thread(target=GetLockOrTimeOut)
    thread.start()
    thread.join(timeout)

    if thread.isAlive():
        print 'GetLock timed out'
        return False
    else:
        return True

我已经研究了终止线程的解决方案,最流行的解决方案似乎是对threading.thread进行子类化,并添加一个在线程中引发异常的功能。但是,我遇到了一个link,它说这个方法不能与本机调用一起工作,我非常确定fcntl.flock()正在调用本机函数。有什么建议吗?

上下文:我使用文件锁来创建一个单实例应用程序,但我不希望该应用程序的第二个实例在第一个实例终止之前一直处于挂起状态。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-03-10 12:30:31

系统调用的超时是通过信号完成的。当信号发生时,大多数阻塞系统调用都会返回EINTR,因此可以使用alarm实现超时。

这里有一个上下文管理器,它可以处理大多数系统调用,如果它花费的时间太长,会导致IOError从阻塞的系统调用中引发。

代码语言:javascript
复制
import signal, errno
from contextlib import contextmanager
import fcntl

@contextmanager
def timeout(seconds):
    def timeout_handler(signum, frame):
        pass

    original_handler = signal.signal(signal.SIGALRM, timeout_handler)

    try:
        signal.alarm(seconds)
        yield
    finally:
        signal.alarm(0)
        signal.signal(signal.SIGALRM, original_handler)

with timeout(1):
    f = open("test.lck", "w")
    try:
        fcntl.flock(f.fileno(), fcntl.LOCK_EX)
    except IOError, e:
        if e.errno != errno.EINTR:
            raise e
        print "Lock timed out"
票数 25
EN

Stack Overflow用户

发布于 2011-03-10 11:50:15

我确信有几种方法,但是使用非阻塞锁怎么样?尝试n次后,放弃并退出吗?

要使用非阻塞锁,请包括fcntl.LOCK_NB标志,如下所示:

代码语言:javascript
复制
fcntl.flock(self.__lock_file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
票数 10
EN

Stack Overflow用户

发布于 2015-09-15 15:32:58

我喜欢在这里蜂拥而至,因为尝试使用超时进行阻塞锁需要更改全局状态,这使得对您的程序进行推理变得更加困难,特别是在涉及线程的情况下。

您可以像上面那样派生子进程并实现警报,也可以只执行http://man7.org/linux/man-pages/man1/flock.1.html

代码语言:javascript
复制
import subprocess
def flock_with_timeout(fd, timeout, shared=True):
    rc = subprocess.call(['flock', '--shared' if shared else '--exclusive', '--timeout', str(timeout), str(fd)])
    if rc != 0:
        raise Exception('Failed to take lock')

如果您有一个足够新的flock版本,您可以使用-E为命令指定一个不同的退出代码,否则命令会成功,但在超时后无法获得锁,因此您可以知道命令是否由于其他原因而失败。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5255220

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档