问题陈述:
我有一个从外部工具调用的脚本,并在一组文件中维护其实例的状态。我认为处理它的最实用的方法是使用单个锁来简单地序列化脚本实例,该锁具有以下能力:(a)尚未锁定时,(b)释放后和(c) )在持有它的进程消失后。
我还不确定当现有进程崩溃或其他情况时是否有必要立即唤醒下一个等待进程,因为无论如何这是一种异常(exception)情况。但肯定的是,下一个操作(可能由重新启动触发)必须能够成功运行。
该脚本依赖于 NetworkManager,而 NetworkManager 目前仅在 Linux 上运行。因此,简单的解决方案优于跨平台解决方案。另一方面,跨平台解决方案可能对大量 stackoverflow 访问者有用。
进一步讨论:
我在 stackoverflow 上找到了许多相关的问题和答案,但是 (1) 这些问题不像这个问题那么具体,并且 (2) 答案似乎不适用于本案例。尤其是有关处理过时锁的部分大部分都没有得到解决。
我想继续使用上下文管理器 API,并且仅使用 Linux 安装中常见的库。我想标准库和任何常见安装中都没有完美的解决方案,所以我想我需要使用一些较低级别的 API 来实现上下文管理器。
当前代码使用lockfile模块,它似乎根本不关心过时的锁。除了文件系统之外,脚本实例不会共享任何内容,因此基于多处理模块的解决方案似乎不适用于此处。我正在考虑 pidfile 和 fcntl 的组合,而且还考虑可用于等待其他脚本完成的 unix 套接字 。我想知道为什么我在 Python 中找不到一个基于标准上下文管理器的工具。
相关脚本的实时版本(将随着新补丁的接受而更改):
http://www.nlnetlabs.nl/svn/dnssec-trigger/trunk/dnssec-trigger-script.in
相关部分源码:
def run(self):
with lockfile.FileLock("/var/run/dnssec-trigger/dnssec-trigger"):
log.debug("Running: {}".format(self.method.__name__))
self.method()
最佳答案
您可以使用 contextlib
创建自己的上下文管理器,并使用 fcntl
发出锁定调用。请注意,这些可以设为非阻塞。
contextlib
和 fcntl
都是标准库的一部分。
为了尝试使用过时的锁,您可以尝试启动该进程两次并向其中之一发出 SIGKILL — 您应该看到锁在另一个进程上被释放。
import fcntl
import contextlib
@contextlib.contextmanager
def lock(fname):
with open(fname, "w") as f:
print "Acquiring lock"
fcntl.lockf(f, fcntl.LOCK_EX)
print "Acquired lock"
yield
print "Releasing lock"
fcntl.lockf(f, fcntl.LOCK_UN)
print "Released lock"
if __name__ == "__main__":
import os
print "PID:", os.getpid()
import time
print "Starting"
with lock("/tmp/lock-file"):
time.sleep(100)
print "Done"
关于python - 如何在Python中正确实现基于进程的锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24797011/