使用flock、fork和终止父进程时的死锁问题
我有一个比较复杂的Python程序。内部有一个日志系统,它使用一种独占的锁(LOCK_EX
)通过fcntl.flock
来管理全局锁。简单来说,每当有日志信息要写入时,程序会先获取全局文件锁,然后把信息写入一个文件(这个文件和锁文件是不同的),最后再释放全局文件锁。
这个程序还会自己分叉几次(在设置好日志管理之后)。通常来说,一切都运行得很顺利。
但是,如果父进程被杀掉了(而子进程还在运行),我有时会遇到死锁的情况。所有的程序都会在fcntl.flock()
这里卡住,永远无法继续。即使我尝试从外部获取锁,也会一直卡住。为了修复这个问题,我不得不杀掉子进程。
更让人困惑的是,使用lsof lock_file
命令时,显示没有任何进程持有这个锁!所以我搞不清楚为什么文件会被内核锁住,但又没有任何进程被报告为持有它。
难道flock
在分叉时会有问题吗?死掉的父进程是否以某种方式仍然持有这个锁,即使它已经不在进程表中了?我该如何解决这个问题呢?
1 个回答
4
lsof
这个工具可能根本就不显示 flock()
的锁,所以如果你没看到锁,并不能说明没有锁存在。
flock()
的锁是通过文件描述符共享来继承的(比如使用 dup()
系统调用,或者在创建子进程时保持文件打开),任何拥有这个共享描述符的人都可以解锁这个锁。但是如果这个锁已经被别人占用,再去锁它就会被阻塞。所以,很可能是父进程锁住了这个描述符,然后结束了,导致这个描述符一直被锁着。接着,子进程也想去锁这个描述符,但因为它已经被锁住了,所以会被阻塞。(如果是子进程先锁住了文件,然后结束,情况也是一样的。)
而 fcntl()
的锁是针对每个进程的,死掉的进程会释放它所有的锁,这样你就可以继续进行,这正是你想要的结果。