使用flock、fork和终止父进程时的死锁问题

7 投票
1 回答
3296 浏览
提问于 2025-04-17 12:10

我有一个比较复杂的Python程序。内部有一个日志系统,它使用一种独占的锁(LOCK_EX)通过fcntl.flock来管理全局锁。简单来说,每当有日志信息要写入时,程序会先获取全局文件锁,然后把信息写入一个文件(这个文件和锁文件是不同的),最后再释放全局文件锁。

这个程序还会自己分叉几次(在设置好日志管理之后)。通常来说,一切都运行得很顺利。

但是,如果父进程被杀掉了(而子进程还在运行),我有时会遇到死锁的情况。所有的程序都会在fcntl.flock()这里卡住,永远无法继续。即使我尝试从外部获取锁,也会一直卡住。为了修复这个问题,我不得不杀掉子进程。

更让人困惑的是,使用lsof lock_file命令时,显示没有任何进程持有这个锁!所以我搞不清楚为什么文件会被内核锁住,但又没有任何进程被报告为持有它。

难道flock在分叉时会有问题吗?死掉的父进程是否以某种方式仍然持有这个锁,即使它已经不在进程表中了?我该如何解决这个问题呢?

1 个回答

4

lsof 这个工具可能根本就不显示 flock() 的锁,所以如果你没看到锁,并不能说明没有锁存在。

flock() 的锁是通过文件描述符共享来继承的(比如使用 dup() 系统调用,或者在创建子进程时保持文件打开),任何拥有这个共享描述符的人都可以解锁这个锁。但是如果这个锁已经被别人占用,再去锁它就会被阻塞。所以,很可能是父进程锁住了这个描述符,然后结束了,导致这个描述符一直被锁着。接着,子进程也想去锁这个描述符,但因为它已经被锁住了,所以会被阻塞。(如果是子进程先锁住了文件,然后结束,情况也是一样的。)

fcntl() 的锁是针对每个进程的,死掉的进程会释放它所有的锁,这样你就可以继续进行,这正是你想要的结果。

撰写回答