python 文件锁_为什么python里面的flock锁不住文件?注意变量的作用域

本文探讨了Python中flock文件锁的工作原理,指出在使用fcntl.flock时,由于Python的引用计数GC机制,当局部变量作用域结束,文件会自动关闭,导致锁失效。解决方案是使用全局变量保存文件描述符,以维持文件锁定状态。总结强调在使用flock时要注意变量作用域,防止因文件关闭导致锁失效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0x01 flock的基本工作原理

首先,我们直接使用flock命令看下flock是怎样工作的.

在一个窗口中运行如下命令,其中--verbose会导致flock输出锁文件的详细过程,-n表示non block,也就是如果这个文件无法lock住,进程直接非0退出,而不是一直等待.可以看到正常lock住这个文件了.

#flock --verbose -n test.lock bash -c 'echo lock ok; sleep 100'
d0ec3f00e0793ac600731789cd74d44a.png

窗口1中运行的flock命令,成功

同时,在另外一个窗口也敲这条命令,发现lock失败了,这个符合我们的预期.

6b3f9e2027d82a27f53d33fe25bebd56.png

窗口2中同样的flock命令,失败

为了看到文件锁的详细情况,我们使用lsof来看下第一个窗口flock进程打开的文件,可以看到test.lock这个文件在FD这一列有一个W,表示整个文件被上了一个write lock.所以第二个窗口的flock就无法锁住了

#lsof -p 17997
1434bbb1fc4ade7a4301becc2bdfcc26.png

lsof显示窗口1中的flock进程锁住了文件

0x02 在python中使用flock

python中可以使用标准库里面的fcntl.flock来锁文件.我们先尝试用同样的方法来lock一个文件.python进程启动之后直接对/var/run/test.lock1文件进行lock,成功之后运行主程序代码.

4f7ac4c5cef8ce86877b27a1e2ee36cf.png

有问题的flock代码

然后在两个窗口中运行代码,发现都能跑到主要代码,说明文件没有lock住! 这个是怎么回事?

3523f0ffec0f66669adcb731fd804a1b.png

窗口1中的代码运行

ce56625088d7d785a4bf70b307e66054.png

窗口2中的代码运行

使用lsof看下两个进程打开文件的情况,很奇怪,没有发现/var/run/test.lock1! 但是程序的日志显示打开了的啊.

804347d875874397a17c7df6d9804205.png

0x03 python使用引用计数进行GC,会自动关闭文件

遇到这种奇怪的问题,祭出我们的神器strace对系统调用进行一下追踪.

#strace python3 tflock.py &>/tmp/aa

从strace的输出可以看到,/var/run/test.lock1被打开了,然后flock给它上了一个互斥锁,然后就被关闭了.

c75b51ed2154605726d6529c90f08ccd.png

strace显示,文件lock之后被关闭了

看一下我们的代码,里面没有对close(fd)的调用,为什么文件会被关闭了呢?

python解释器自带GC,而且是引用计数GC.也就是当一个对象的引用计数为0的时候,自动被释放.我们的fd是定义在lockFile1函数中的,当这个函数执行完成,其作用域就没有了,fd对应的open file引用计数变成0,其资源会被释放. 对于open file来说,其释放过程包含了对fd的close调用,这就是为什么代码里面没有close(fd),但是文件被关闭了.

那文件被关闭为什么会导致文件的锁也没有了呢?

在man 2 flock中有如下一段话,flock在显示调用LOCK_UN和所有fd都关闭的情况会被释放.

Furthermore, the lock is released either by an explicit LOCK_UN operation on any of these duplicate file descriptors, or when all such file descriptors have been closed.

0x04 使用全局变量保持文件开启

知道原因之后解决这个问题就比较简单了,既然函数中的局部变量会在函数返回之后就没有了,那么用全局变量即可.

给变量fd加上global声明.

6fe63a1cb6ec8e7357abdea03af906b9.png

正确的flock代码,fd声明global

这样第二个窗口运行的时候直接就报错BlockingIOError了,锁不住文件

19f860a8e942585ae623d2689dd3c72f.png

第二个窗口文件锁不住了

lsof显示第一个窗口的python3进程成功锁住了文件.

b92b4be3860db05439d4e6dfbc5780d4.png

第一个窗口成功锁住文件

0xff 总结

flock用来保持一个程序只有一个进程在运行时很有用.但是在python中使用flock一定要注意python对变量作用域的处理,一定要将open函数返回的fd存放在全局变量而不是局部变量中,避免python解释器的GC把文件自动close导致锁失效.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值