最可靠的方法是用flock()尝试加非阻塞共享锁:先open()获取fd,再flock(fd, LOCK_SH|LOCK_NB),若返回-1且errno==EWOULDBLOCK,说明文件正被其他进程以排他方式锁定;检测后立即close(fd)即可。

最可靠的方法是用 flock() 尝试加一个非阻塞共享锁。失败且错误码为 EWOULDBLOCK,基本说明文件正被其他进程以独占方式锁定(比如正在写入)。
用 flock() 检测独占锁(Linux/macOS)
这是系统级、轻量、直接的方式,不依赖外部工具或扫描进程。
- 先用
open("/path/to/file", O_RDONLY)获取文件描述符(fd),路径必须是绝对路径 - 调用
flock(fd, LOCK_SH | LOCK_NB):尝试非阻塞加共享锁 - 若返回 -1 且
errno == EWOULDBLOCK,说明已有进程持有LOCK_EX(排他锁),即被独占锁定 - 检测完立即
close(fd)即可,无需保持 fd 打开 - 注意:flock 是建议性锁,但主流工具(rsync、logrotate、多数日志库)都遵循它,因此实际覆盖度高
为什么不用 stat() 或 ls -l?
这些命令只看文件元数据(权限、大小、时间戳),完全不反映当前锁状态。即使文件正被写入并加了排他锁,stat 也看不出任何异常。
- 文件锁是内核维护的运行时状态,不存于磁盘或 inode 中
-
ls -l显示的是文件权限位,和 flock/fcntl 锁无关 - 试图通过修改时间判断“是否刚被写”容易误判——写入可能已结束,锁却未释放
辅助验证:查谁在用这个文件
当需要知道具体是哪个进程在加锁时,配合 lsof 可定位源头。
- 运行
sudo lsof /absolute/path/to/file(必须用绝对路径 + sudo) - 关注 FD 列:出现
REG且带w(如REG-W)或u(读写),表示该进程正在写或读写该文件 - NAME 列末尾有
(deleted)表示文件已被删但句柄未关,此时仍可能持锁 - 如果 lsof 无结果,大概率是权限不足(普通用户看不到 root 进程)或路径不准确
补充说明:flock 的局限性
它不能捕获所有写入行为,但对常规场景足够有效。
- 仅对使用 flock/fcntl 加锁的进程敏感;绕过锁机制直接 write() 的程序不会被拦住(但这类行为本身就不规范)
- 某些编辑器(如 vim 临时写新文件再 rename)或简单脚本(echo > file)可能不加锁,此时检测不到,但它们也不构成“持续独占”
- 不适用于 NFS 等网络文件系统(flock 在 NFS 上不可靠,应改用 fcntl)


















