Python的fcntl.flock函数是否提供文件访问的线程级锁定?

2 投票
1 回答
5707 浏览
提问于 2025-04-16 05:16

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 个回答

6

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 中通常是同样处理的。大多数情况下,如果一个系统调用文档中提到进程间的父子行为,线程也是如此。

当然,你可以(而且可能应该)自己测试一下这种行为。

撰写回答