python lockf和flock行为
Posted
技术标签:
【中文标题】python lockf和flock行为【英文标题】:python lockf and flock behaviour 【发布时间】:2015-04-12 18:17:42 【问题描述】:关于flock
/lockf
/fcntl
之间的区别,我已经阅读了足够多关于*** 的帖子,但我无法回答以下观察:
>>> import fcntl
>>> a = open('/tmp/locktest', 'w')
>>> b = open('/tmp/locktest', 'w')
>>> fcntl.lockf(a, fcntl.LOCK_EX | fcntl.LOCK_NB)
>>> fcntl.lockf(a, fcntl.LOCK_EX | fcntl.LOCK_NB)
>>> fcntl.lockf(b, fcntl.LOCK_EX | fcntl.LOCK_NB)
>>>
>>> a.close()
>>> b.close()
>>> a = open('/tmp/locktest', 'w')
>>> b = open('/tmp/locktest', 'w')
>>> fcntl.flock(a, fcntl.LOCK_EX | fcntl.LOCK_NB)
>>> fcntl.flock(a, fcntl.LOCK_EX | fcntl.LOCK_NB)
>>> fcntl.flock(b, fcntl.LOCK_EX | fcntl.LOCK_NB)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 35] Resource temporarily unavailable
为什么这两种情况的行为不同?我知道显而易见的答案是,这是两种不同的锁定机制。我正在寻找:
-
实际上
lockf()
或flock()
对文件 (inode/fd
) 做了什么?
根据演示,我们是否允许递归获取相同的锁?
我了解fds
的基础知识和其他内容,因此我希望获得对操作系统级别细节有更多见解的技术答案。
OSX 10.9.3,Python:2.7.5
【问题讨论】:
我冒昧地编辑了问题以实际包含一个问题。如果这不是您要的,请查看和编辑。谢谢。 @NPE:这是我第一句话的一部分,但最好明确地放在那里。谢谢:) 【参考方案1】:一篇关于这个的好文章: On the Brokenness of File Locking
简而言之:
POSIX 锁:
lockf() 大多数时候只是作为 fcntl() 的一个接口实现
fcntl() 锁绑定到进程,而不是文件描述符。 如果一个进程对特定文件有多个打开的文件描述符,则这些用于获取锁定的文件描述符中的任何一个都将RESET锁定。
BSD 锁:
flock() 锁绑定到文件描述符,而不是进程。
此外
一个很好的测试分析: Advisory File Locking – My take on POSIX and BSD locks
摘要摘录:
fcntl 和flock 样式锁彼此完全正交。任何同时提供两者的系统(Linux 提供)都将独立处理通过它们中的每一个获得的锁。 当进程退出或中止时,POSIX 和 BSD 锁都会自动释放。 POSIX 和 BSD 锁在 execve 调用中都会保留,除非进程设置了 FD_CLOEXEC 标志,强制关闭文件描述符,并且不被新进程继承。
【讨论】:
公平的评估。应该强调的是,POSIX 锁在多线程场景下静默失败,并且应该(可以说)被认为对在现代软件堆栈中使用有害——尽管GIL。更重要的是,应该强调对组可读文件或全球可读文件的 POSIX 和 BSD 锁定都会带来极大的安全风险。 为什么?因为 任何 对要锁定的文件具有读取权限的用户都可以通过先抢先获取该锁然后再不释放它来永久死锁您的 Python 应用程序。 tl;dr: (A) 内存锁(例如,multiprocessing
module 同步原语)比 BSD- 和POSIX 样式的锁,(B) BSD 样式的 flock
锁比 POSIX 样式的 fcntl
锁更可取,并且 (C) 既不是 BSD 也不是 POSIX除非要锁定的文件的权限严格限制为最多 0600
,否则应使用 -style 锁。
我要添加到这个答案的唯一一件事是注意您正在使用 fcntl.LOCK_NB
标志。如果您删除此标志,那么您的第二种情况将阻塞而不是引发异常。
另外,如果你在另一个窗口中运行另一个 python 会话,并在文件上使用 lockf() 并保持文件打开,那么你会发现异常发生在第一次调用 @987654333 @,在您的第二次会话中(如果我们重新使用 fcntl.LOCK_NB
)。这确认了fcntl.lockf()
进程全局的状态,而fcntl.flock()
的状态由文件描述符限定。
关于 @CecilCurry 的链接,请注意 Python 多处理模块仅适用于同步 由共同父进程生成的 Python 子进程,如果其中一个进程崩溃 this leaks semaphores and shared memory segments 和 corrupts Queue objects 和 pipes。以上是关于python lockf和flock行为的主要内容,如果未能解决你的问题,请参考以下文章
Linux文件锁学习-flock, lockf, fcntl
Linux 下三种文件锁 —— fcntl/lockf、flock