Linux文件锁是内核提供的同步原语,作用于fd或inode,分建议锁(flock/fcntl,依赖进程自觉)和强制锁(需挂载mand选项,内核强校验);flock轻量、全文件、随fd生命周期,fcntl支持字节范围锁、更精细;读锁共享、写锁互斥,不可升级;典型应用包括日志原子写入、配置文件串行更新、单实例守护进程控制。

Linux文件锁本质是内核提供的同步原语,不依赖文件内容本身,而是作用于打开的文件描述符(fd)或inode。它解决的核心问题是:当多个进程同时访问同一文件时,如何避免数据错乱、覆盖或读到中间状态。
两类锁机制:建议锁与强制锁
Linux支持两种文件锁策略,适用场景差异明显:
-
建议性锁(Advisory Lock):最常用。内核不强制拦截,仅靠进程主动调用
flock()或fcntl()检查并遵守锁状态。所有参与进程必须“守规矩”,否则锁形同虚设。Python、C、Shell脚本中普遍使用此方式。 -
强制性锁(Mandatory Lock):需文件系统挂载时启用
mand选项(如mount -o remount,mand /path),且目标文件须设置setgid位且组执行位关闭(chmod g+s,g-x file)。内核会在每次read()/write()前自动校验锁,但带来明显性能开销,生产环境极少启用。
两种主流API:flock vs fcntl
实际开发中主要用以下两个系统调用,特性不同,不可混用:
-
flock():操作对象是整个文件,基于文件描述符,轻量易用。锁随fd生命周期存在——
fork()后子进程继承锁,close()即自动释放。适合日志写入、单例控制等简单互斥场景。 -
fcntl():功能更强大,支持字节范围锁(record locking),可对文件某一段加读锁或写锁。锁与fd绑定但不随
fork()继承;需显式调用F_SETLK(非阻塞)或F_SETLKW(阻塞等待);close()同样自动释放。适合配置文件部分更新、数据库记录级并发等精细控制。
读锁与写锁的行为逻辑
无论用哪种API,锁类型都遵循统一语义:
- 共享锁(F_RDLCK / LOCK_SH):允许多个进程同时持有,用于安全读取。只要存在任一共享锁,其他进程无法获得独占锁。
- 独占锁(F_WRLCK / LOCK_EX):严格互斥,同一时间最多一个进程持有。获取时会阻塞直到所有共享锁和独占锁释放。
- 锁升级/降级不可行:不能在已持共享锁的前提下直接转为独占锁(会死锁),必须先释放再重新申请。
典型多进程并发问题与锁应对
三个高频场景说明锁的实际价值:
-
日志行交错:多个进程用
open(...O_APPEND)写同一日志,因缓冲与调度导致多行粘连。加flock(fd, LOCK_EX)再write(),确保每条日志原子落盘。 -
配置文件竞态更新:A读config.json→修改→写回;B同时执行相同流程。若无锁,B可能覆盖A的修改。用
fcntl()在写入前加全文件独占锁,保证更新串行化。 -
单实例守护进程:启动时尝试对固定锁文件(如
/var/run/mydaemon.lock)加独占锁,失败即说明已有实例运行,直接退出。










