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

云计算分享者 2024-02-24 02:14:02
0x01 flock的基本工作原理

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

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

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

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

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

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

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

#lsof -p 17997

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

0x02 在python中使用flock

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

有问题的flock代码

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

窗口1中的代码运行

窗口2中的代码运行

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

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

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

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

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

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声明.

正确的flock代码,fd声明global

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

第二个窗口文件锁不住了

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

第一个窗口成功锁住文件

0xff 总结

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

0 阅读:0

云计算分享者

简介:感谢大家的关注