如何在没有竞争条件的情况下删除锁定的(flock)文件:在释放锁之前或之后?
How to delete a locked (flock) file without race condition: before or after releasing the lock?
我正在实现基于文件锁的互斥机制。我的脚本的其他实例知道当它们遇到一个被锁定的特定文件时,它们不应该 运行。
为了实现这一点,我使用 fcntl.flock
创建并锁定了文件。当我释放锁时,我还想清理文件,当实际上没有进程 运行ning.
时,它不会坐在那里指示旧 pid
我的问题是,我应该何时以及如何清理文件,特别是在什么时候可以删除它。基本上我看到两个选项:
- t运行在释放锁之前删除文件
- t运行解锁后删除文件
据我了解,每一个都将我的应用程序暴露在略有不同的竞争条件下。什么是最佳实践,我错过了什么?
这是一个(过于简化的)示例:
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?
我找到了这个相关问题来提供一些关于如何处理这种情况的建议:
- flock(): removing locked file without race condition?
这也让我意识到了另一种可能的竞争条件,当另一个进程在当前进程打开文件后立即删除该文件时,就会发生这种情况。
这将导致当前进程锁定文件系统中不再存在的文件,从而无法阻止将重新创建它的下一个进程。
在那里我发现了使用打开标志 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)
实施后,我发现这与 lockfile
模块用于其 pid 文件的方法完全相同。
供参考:
- 在 unix 中,可以在文件打开时删除它 - ino 将一直保留到所有进程结束,并且在其文件描述符列表中有它
- 在 unix 中,可以通过检查 link 计数变为零来检查文件是否已从所有目录中删除
当每次都创建锁文件时,这可能是 unix 下的有效解决方案:
import fcntl
import os
import sys
import time
# open file for read/write, create if necessary
for attempt in xrange(timeout):
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)
st = os.fstat(f)
if not st.st_nlink:
print 'lock file got deleted'
continue # try again
except BlockingIOError:
print 'other process running:', f.readline()
time.sleep(1)
continue # try again
try:
# do something
f.write('%d\n' % os.getpid())
f.flush()
# more stuff here ...
time.sleep(5)
finally:
# clean up here
os.unlink('my_lock_file.pid')
# release lock
fcntl.flock(f, fcntl.LOCK_UN)
return True
return False
作业:解释为什么删除文件的传统名称在 unix 中被命名为 "unlink"。
我正在实现基于文件锁的互斥机制。我的脚本的其他实例知道当它们遇到一个被锁定的特定文件时,它们不应该 运行。
为了实现这一点,我使用 fcntl.flock
创建并锁定了文件。当我释放锁时,我还想清理文件,当实际上没有进程 运行ning.
我的问题是,我应该何时以及如何清理文件,特别是在什么时候可以删除它。基本上我看到两个选项:
- t运行在释放锁之前删除文件
- t运行解锁后删除文件
据我了解,每一个都将我的应用程序暴露在略有不同的竞争条件下。什么是最佳实践,我错过了什么?
这是一个(过于简化的)示例:
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?
我找到了这个相关问题来提供一些关于如何处理这种情况的建议:
- flock(): removing locked file without race condition?
这也让我意识到了另一种可能的竞争条件,当另一个进程在当前进程打开文件后立即删除该文件时,就会发生这种情况。 这将导致当前进程锁定文件系统中不再存在的文件,从而无法阻止将重新创建它的下一个进程。
在那里我发现了使用打开标志 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)
实施后,我发现这与 lockfile
模块用于其 pid 文件的方法完全相同。
供参考:
- 在 unix 中,可以在文件打开时删除它 - ino 将一直保留到所有进程结束,并且在其文件描述符列表中有它
- 在 unix 中,可以通过检查 link 计数变为零来检查文件是否已从所有目录中删除
当每次都创建锁文件时,这可能是 unix 下的有效解决方案:
import fcntl
import os
import sys
import time
# open file for read/write, create if necessary
for attempt in xrange(timeout):
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)
st = os.fstat(f)
if not st.st_nlink:
print 'lock file got deleted'
continue # try again
except BlockingIOError:
print 'other process running:', f.readline()
time.sleep(1)
continue # try again
try:
# do something
f.write('%d\n' % os.getpid())
f.flush()
# more stuff here ...
time.sleep(5)
finally:
# clean up here
os.unlink('my_lock_file.pid')
# release lock
fcntl.flock(f, fcntl.LOCK_UN)
return True
return False
作业:解释为什么删除文件的传统名称在 unix 中被命名为 "unlink"。