【问题标题】:Can I prevent a script from launching twice using open(2) with O_CREAT and flock(2)?我可以使用带有 O_CREAT 和 flock(2) 的 open(2) 来阻止脚本启动两次吗?
【发布时间】:2015-07-10 20:34:50
【问题描述】:

我想通过使用 PID 文件来防止脚本启动两次。实现排他性的方法有很多,但由于我的脚本将始终在 Linux 机器上运行,并且我希望能够自动检测过时的 PID 文件,因此我想使用flock(2) 来实现这一点。

很久以前,一位同事告诉我,以下伪代码是执行此操作的正确方法(open(..., 'w') 表示“使用O_CREAT 以写入模式打开”):

fd = open(lockfile, 'w');
write(fd, pid);
close(fd);
fd = open(lockfile);
flock(fd)
file_pid = read(fd)
if file_pid != pid:
    exit(1)
// do things

我很好奇他为什么建议上面而不是:

fd = open(lockfile, 'w')
flock(fd)
// do things

大概是因为他认为open(2)O_CREAT 的“如果文件不存在就创建文件”功能不是原子的,也就是说,两个进程同时调用open(2) 可能获取两个不同文件的句柄,因为文件创建不是独占的。

我的问题是,后面的代码在 Linux 系统上是否总是正确的,或者如果不是,什么时候不正确?

【问题讨论】:

  • 我可以肯定伪代码是错误的。除此之外,flock() 锁定通常(几乎总是)是监督性的,而不是强制性的。这段代码似乎在文件中写入了新进程的 PID,即使旧进程仍在使用它。仅此一项就引起悲伤。我在 SO 上没有找到一个很好的“如何进行锁定”问答,这有点令人惊讶,虽然我只寻找了“lockfile”,所以还不能说我已经彻底搜索过。
  • 只要您不希望文件包含当前拥有锁的进程的确切 pid,代码应该是正确的。我不知道你说的“监督锁”是什么意思,你说的是“咨询锁”吗?如果这就是您的意思,那么只要两个进程都成群结队(),它仍然无关紧要。什么情况下会发生错误(两个进程同时到达伪代码的第 9 行)?
  • 对于我的 'supervisory',请使用 'advisory' - 抱歉用错了术语。
  • 锁文件的全部意义在于包含了文件被锁的进程的PID,这样锁文件的读取者可以检查该进程是否还存在,如果存在则接管锁它不是。因此,文件中的 PID 错误是非常错误的。
  • 似乎file locking with lock files 上的维基百科会声称我夸大了我的情况。但是,该部分有点脆弱(例如,它没有提供伪代码算法),并且肯定有很多方法可以使用锁定文件进行锁定 - 不一定都像每个一样有效或有弹性其他。

标签: linux unix daemon


【解决方案1】:

flock 并非 100% 可靠:http://en.wikipedia.org/wiki/File_locking#Problems

第一个配方相当具有侵入性,因为后续调用进程可能会盲目地覆盖先前调用写入的 pid 数据,从而有效地阻止第一个进程运行。因此,在高重复调用率下,可能没有进程运行。

为确保文件创建排他性,请使用 O_CREAT | O_EXCL。您需要处理不合时宜的进程死亡而留下文件。

我建议 2 个文件:

  • 使用 O_CREAT 打开的锁定文件 | O_EXCL,仅用于保护实际的PID文件操作,应该只存在很短的时间,很容易根据创建时间判断是否过期。
  • 实际的 PID 文件

每个进程等待锁定文件消失(当它变得陈旧时清除它),然后尝试创建锁定文件(只有一个实例成功,其他实例等待),检查 PID 文件的存在/内容(清理并如果过时则删除它),如果决定运行则创建一个新的 PID 文件,然后删除锁定文件并按决定运行/退出。

【讨论】:

  • 感谢您的回答,这是一个很好的解决方案。你知道关于使用 O_CREAT 但没有 O_EXCL 打开部分的答案吗?如,假设flock是可靠的,第二个伪代码sn-p是否有效?
  • 充其量它可能只能序列化多个实例的执行,但不能阻止后续执行,如果没有 O_EXCL,后续执行会在flock 处阻塞并在第一个进程出于任何原因退出时继续。恕我直言,很难实现可靠的逻辑。
  • 你的解决方法和perlFile::NFSLock差不多,我写的时候用的,是不是同时失效了NFS缓存?
  • 我不能 100% 确定尝试读取其他文件是否仍不会使用缓存。 可能通过在该目录中创建文件来刷新缓存的目录条目(至少我的观察似乎支持这一点)。它还可能取决于实际的客户端和/或服务器 NFS 实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-21
  • 2016-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多