【发布时间】: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 上的维基百科会声称我夸大了我的情况。但是,该部分有点脆弱(例如,它没有提供伪代码算法),并且肯定有很多方法可以使用锁定文件进行锁定 - 不一定都像每个一样有效或有弹性其他。