如何在没有竞争条件的情况下删除锁定(群)文件:在释放锁定之前或之后?

moo*_*eep 6 python ipc flock delete-file

我正在实现基于文件锁的互斥机制。我的脚本的其他实例知道,当它们遇到被锁定的特定文件时,它们不应该运行。

为了实现这一点,我使用fcntl.flock. 当我释放锁时,我还想清理文件,当没有进程实际运行时,它不会坐在那里指示旧的 pid。

我的问题是,我应该何时以及如何清理文件,尤其是在什么时候可以删除它。基本上我看到两个选项:

  • 在释放锁之前截断并删除文件
  • 释放锁后截断并删除文件

根据我的理解,每一个都将我的应用程序暴露在略有不同的竞争条件下。什么是最佳实践,我错过了什么?

这是一个(过于简化的)示例:

import fcntl
import os
import sys
import time

# open file for read/write, create if necessary
with open('my_lock_file.pid', 'a+') as f:
    # acquire lock, raises exception if lock is hold by another process
    try:
        fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
    except IOError:
        print 'other process running:', f.readline()
        sys.exit()

    try:
        # do something
        f.write('%d\n' % os.getpid())
        f.flush()
        # more stuff here ...
        time.sleep(5)
    finally:
        # clean up here?
        # release lock
        fcntl.flock(f, fcntl.LOCK_UN)
        # clean up here?
# clean up here?
Run Code Online (Sandbox Code Playgroud)

moo*_*eep 3

我发现这个相关问题给出了一些关于如何处理这种情况的建议:

它还让我意识到另一种可能的竞争条件,当另一个进程在当前进程打开文件后立即删除该文件时,就会发生这种情况。这将导致当前进程锁定在文件系统上不再找到的文件,从而无法阻止下一个重新创建该文件的进程。

在那里,我发现了使用 open 标志进行原子独占文件创建的建议,该标志通过低级文件操作的函数O_EXCL公开。os.open()然后我相应地实现了以下示例:

import os
import sys
import time

# acquire: open file for write, create if possible, exclusive access guaranteed
fname = 'my_lock_file.pid'
try:
    fd = os.open(fname, os.O_CREAT|os.O_WRONLY|os.O_EXCL)
except OSError:
    # failed to open, another process is running
    with open(fname) as f:
        print "other process running:", f.readline()
        sys.exit()

try:
    os.write(fd, '%d\n' % os.getpid())
    os.fsync(fd)
    # do something
    time.sleep(5)
finally:
    os.close(fd)
    # release: delete file
    os.remove(fname)
Run Code Online (Sandbox Code Playgroud)

lockfile实现后,我发现这与模块用于其 pid 文件的方法完全相同。

以供参考:

  • 如果脚本在“执行某些操作”步骤期间异常退出,则锁定文件不会被删除。以后所有运行该脚本的尝试都将打印“其他进程正在运行”消息,因为如果文件已存在,“os.O_EXCL”会导致发生错误。因此,[fasteners](http://fasteners.readthedocs.io/en/latest/api/process_lock.html)包中提供的进程锁等其他方法不会清理锁定文件。如果您想允许删除锁定文件,我认为您需要在获取锁定后对文件进行统计,正如您链接到的答案中所建议的那样。 (2认同)