Python的fcntl.flock函数是否提供文件访问的线程级锁定?
Python的fcnt模块提供了一种叫做[flock][1]的方法,用于文件锁定。它的描述是:
在文件描述符fd上执行锁定操作op(提供fileno()方法的文件对象也可以接受)。详细信息请查看Unix手册中的flock(2)。(在某些系统上,这个功能是通过fcntl()模拟实现的。)
查阅Linux的man手册,flock主要是用于进程间的锁定,比如:
如果另一个进程持有不兼容的锁,调用flock()可能会被阻塞。要进行非阻塞请求,可以在上述操作中加上LOCK_NB(通过OR运算)。
所以我的问题是:flock()是否也能提供线程安全的锁定,能够锁定同一进程中的多个线程,以及来自不同进程的线程呢?
[1]: http://docs.python.org/library/fcntl.html#fcntl.flockfunction 是通过fcntl()模拟实现的。
1 个回答
flock
锁和线程没有关系——其实它也不太关心进程。如果你在两个进程中使用同一个文件描述符(通过 fork 继承过来的),那么任意一个进程用这个文件描述符锁定文件时,两个进程都会获得这个锁。换句话说,在下面的代码中,两个 flock
调用都会成功:子进程锁定了文件,然后父进程也能获得同样的锁,而不是被阻塞,因为它们用的是同一个文件描述符。
import fcntl, time, os
f = open("testfile", "w+")
print "Locking..."
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
print "locked"
fcntl.flock(f.fileno(), fcntl.LOCK_UN)
if os.fork() == 0:
# We're in the child process, and we have an inherited copy of the fd.
# Lock the file.
print "Child process locking..."
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
print "Child process locked..."
time.sleep(1000)
else:
# We're in the parent. Give the child process a moment to lock the file.
time.sleep(0.5)
print "Parent process locking..."
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
print "Parent process locked"
time.sleep(1000)
同样的道理,如果你用不同的文件描述符对同一个文件进行两次锁定,这两个锁会互相阻塞——无论你是在同一个进程还是同一个线程中。参考 flock(2):如果一个进程使用 open(2)(或类似的方式)为同一个文件获取多个描述符,这些描述符在 flock() 中是独立处理的。尝试用其中一个文件描述符锁定文件时,可能会被调用进程已经通过另一个描述符加上的锁拒绝。
记住,对 Linux 内核来说,进程和线程基本上是一样的,它们在内核级的 API 中通常是同样处理的。大多数情况下,如果一个系统调用文档中提到进程间的父子行为,线程也是如此。
当然,你可以(而且可能应该)自己测试一下这种行为。