You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

父进程退出后flock锁提前释放问题及解决方法咨询

问题:flock锁在父进程退出后提前释放,如何保持到父子进程都关闭文件描述符?

我先获取flock锁再执行fork创建子进程,期望锁仅在父子进程均退出后才解锁。但父进程结束后触发断言:

test.lck NOT found in lslocks output
Traceback (most recent call last):
File "daemon_and_flock.py", line 25, in
assert check_lock(path)
AssertionError

相关代码如下:

import fcntl, sys, os, subprocess, time

def check_lock(path: str) -> bool:
    lines = subprocess.check_output(["lslocks"]).decode('utf-8')
    for line in lines.split('\n'):
        if path in line:
            print(f"{path} found in lslocks output")
            return True
    print(f"{path} NOT found in lslocks output")
    return False
        
path = sys.argv[1]
fh = open(path, "a")
fcntl.flock(fh, fcntl.LOCK_EX)
assert check_lock(path)
print(f"before fork: file handle {fh.fileno()}")

pid = os.fork()
if pid == 0:
    print(f"child: file handle {fh.fileno()}")
    assert check_lock(path)
    time.sleep(1)
    assert check_lock(path)
else:
    print(f"parent: file handle {fh.fileno()}")
    assert check_lock(path)

原因分析

flock是进程级锁,内核会在进程退出时自动释放该进程持有的所有flock锁。父进程fork后直接退出,其持有的锁被立即释放,而子进程虽继承了文件描述符,但无法继承父进程的flock锁持有状态,导致子进程的断言失败。

解决方案

要实现“锁保持到所有相关文件描述符关闭”的需求,有两种可行方案:

方案一:改用fcntl文件描述符级记录锁

fcntl的记录锁与文件描述符绑定,只要有一个关联的文件描述符未关闭,锁就会保持。修改后的代码如下:

import fcntl, sys, os, subprocess, time, struct

def check_lock(path: str) -> bool:
    lines = subprocess.check_output(["lslocks"]).decode('utf-8')
    for line in lines.split('\n'):
        if path in line:
            print(f"{path} found in lslocks output")
            return True
    print(f"{path} NOT found in lslocks output")
    return False
        
path = sys.argv[1]
fh = open(path, "a")

# 替换flock为fcntl写锁(覆盖整个文件)
lock_struct = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 0, 0, 0)
fcntl.fcntl(fh, fcntl.F_SETLK, lock_struct)
assert check_lock(path)
print(f"before fork: file handle {fh.fileno()}")

pid = os.fork()
if pid == 0:
    print(f"child: file handle {fh.fileno()}")
    assert check_lock(path)
    time.sleep(1)
    assert check_lock(path)
    fh.close()  # 子进程退出前关闭文件描述符
else:
    print(f"parent: file handle {fh.fileno()}")
    assert check_lock(path)
    fh.close()  # 父进程可提前关闭,锁由子进程保持
    # 可选:若需等待子进程,添加 os.waitpid(pid, 0)

方案二:父进程等待子进程退出(保留flock)

如果必须使用flock,可让父进程阻塞等待子进程结束,确保父进程的锁一直持有到子进程退出:

# 修改原代码的父进程分支
else:
    print(f"parent: file handle {fh.fileno()}")
    assert check_lock(path)
    os.waitpid(pid, 0)  # 等待子进程退出
    assert check_lock(path)

此方案下父进程无法提前退出,需等待子进程结束后才会释放锁。


内容的提问来源于stack exchange,提问作者user1244932

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 17:05:42