多线程/进程直接写同一文件会因写操作非原子性导致错乱、覆盖、截断;flock是内核级建议性锁,需用文件描述符全程包裹写入动作并保持打开,避免子进程释放锁失效。

为什么直接多线程写同一个文件会出问题
多个线程(或进程)同时 fwrite 或 echo >> 同一个文件,不加协调时会出现内容错乱、覆盖、截断——因为写操作不是原子的:open → lseek → write → close 中间可能被抢占。Linux 的 flock 是内核级建议性锁,它不阻止你打开文件,但能让你在关键区前「协商等待」。
flock 在 shell 脚本里怎么用才安全
必须用 flock 包裹整个写入动作,且锁文件描述符要保持打开状态直到写完。常见错误是把 flock 当成命令前缀单独调用,比如 flock /path/file -c 'echo data >> /path/file' —— 这会 fork 子进程,锁在子进程退出后立即释放,根本没保护写入。
- 正确做法:用文件描述符 +
-w设置超时,避免死等:exec 200>/path/lockfile flock -w 5 200 || { echo "lock timeout"; exit 1; } echo "data" >> /path/target.txt flock -u 200 # 显式解锁(可选,fd 关闭时自动释放) - 锁文件不必和目标文件是同一个,但得是同一文件系统上的真实文件(不能是符号链接或 NFS 挂载点,NFS 下
flock可能失效) - 如果脚本异常退出,fd 200 会自动关闭,锁随之释放,这点比
fcntl更省心
在 C/Python 里调用 flock 的关键差异
系统调用 flock() 和 shell 的 flock 命令行为一致,但语言绑定常有坑:
华友协同办公管理系统(华友OA),基于微软最新的.net 2.0平台和SQL Server数据库,集成强大的Ajax技术,采用多层分布式架构,实现统一办公平台,功能强大、价格便宜,是适用于企事业单位的通用型网络协同办公系统。 系统秉承协同办公的思想,集成即时通讯、日记管理、通知管理、邮件管理、新闻、考勤管理、短信管理、个人文件柜、日程安排、工作计划、工作日清、通讯录、公文流转、论坛、在线调查、
- C 中必须对已打开的
int fd调用flock(fd, LOCK_EX),不能对路径名调用;且fork()后子进程会继承锁,但exec()后锁保留(这点和 shell 不同) - Python 的
fcntl.flock()实际调用的是fcntl(F_SETLK),不是flock()系统调用 —— 它在 NFS 上更可靠,但锁类型(LOCK_EX/LOCK_SH)语义相同;而os.system("flock ...")是启动新进程,锁生命周期不跨调用,基本没用 - 所有语言中,锁只对「通过同一 inode 打开的文件描述符」有效;重命名文件不影响锁,但
mv /old /new && echo > /old这种重建操作会丢锁
什么情况下 flock 会失效或不适用
flock 是建议性锁,完全依赖协作。只要有一个写入方不用它,锁就形同虚设。更隐蔽的问题是:
- 容器环境里,若多个容器挂载了同一宿主机路径,但未共享文件系统锁(如 overlayfs),
flock在容器间无效 - Go 默认用
syscall.Flock,但某些构建 tag(如netgo)下可能绕过系统调用,导致锁失效 - 日志轮转工具(如
logrotate)执行mv+touch时,新文件无锁,后续写入直接冲进去——必须让轮转也参与 flock 协商,或改用copytruncate模式
真正需要强一致性时,flock 只是第一道防线;高并发场景建议改用消息队列或单写入进程转发,文件锁只适合低频、短临界区的协作。









