Go标准库无跨平台文件锁,Windows需LockFileEx而Linux/macOS用flock或lockf;推荐用gofrs/flock库,其自动适配各平台机制并处理锁残留问题。

Go 的 flock 和 lockf 在 Windows 上根本不能用
Go 标准库的 os.File 没有跨平台文件锁抽象,flock(Linux/macOS)和 lockf(POSIX)都是系统调用,Windows 完全不支持。直接调用 syscall.Flock 或 syscall.Lockf 会在 Windows 编译失败或 panic。
- Linux/macOS 下
flock是建议性锁(advisory),依赖进程协作;lockf作用于文件描述符,可对文件区域加锁,但也是建议性 - Windows 只认
LockFileEx/UnlockFileEx这套 API,且是强制性锁(mandatory)——但 Go 标准库没封装它 - 跨平台项目若硬写 syscall 层,得自己做 build tag 分支(
//go:build windows///go:build !windows),维护成本高
用 github.com/gofrs/flock 是最省心的跨平台方案
这个库不是简单封装 syscall,而是用不同机制在各平台模拟“互斥文件锁”语义:Linux/macOS 用 flock,Windows 用 CreateFile + LOCKFILE_EXCLUSIVE_LOCK,还处理了进程崩溃后锁残留的问题(通过临时文件 + 进程存活检测)。
- 初始化锁:
l := flock.New("/path/to/lock"),路径必须是绝对路径,相对路径在 Windows 下容易出错 - 加锁:
ok, err := l.Lock(),返回bool表示是否成功(非阻塞),err仅在系统调用失败时非 nil - 解锁:
l.Unlock(),务必 defer 调用,否则锁可能永远不释放 - 注意:它锁的是文件本身,不是文件内容;多个进程锁同一路径才生效,路径不同等于没锁
自己实现要注意 os.O_CREATE | os.O_RDWR 和权限掩码
如果不用第三方库、坚持手写,核心是打开一个锁文件并尝试独占访问。关键不是锁函数,而是文件打开方式和错误判断逻辑。
- 必须用
os.O_CREATE | os.O_RDWR打开锁文件,只读打开无法在 Windows 上触发排他锁 - Linux 下可配合
flock,但要记得fd来自os.OpenFile,不是os.Create(后者默认只写) - Windows 下需用
syscall.CreateFile,传入syscall.FILE_SHARE_NONE,且路径要用\?前缀避免 MAX_PATH 限制(尤其在 CI 环境) - 权限掩码别写死
0600:Windows 忽略 Unix 权限,但 Linux/macOS 上若锁文件被其他用户可写,可能被误删导致锁失效
锁文件路径别放 /tmp,优先用 os.UserCacheDir 或程序工作目录
/tmp 下的锁文件可能被系统定期清理(如 systemd-tmpfiles 清理策略),或被不同用户运行的同名程序干扰。这不是锁机制问题,而是部署现实。
立即学习“go语言免费学习笔记(深入)”;
- 推荐路径:
filepath.Join(os.UserCacheDir(), "myapp", "lock")(用户级隔离)或filepath.Join(workDir, ".lock")(实例级隔离) - 避免用
os.TempDir(),它不保证跨重启持久,也不区分用户 - 锁文件名别带 PID:PID 可能复用,且锁文件应代表“资源占用”,不是“某个进程在跑”
- 如果程序要支持多实例共享锁(比如只允许一个实例写,但多个可读),那就不是文件锁该管的事了——该上分布式协调服务
flock 还是 lockf,而是想清楚你要锁的是“一份配置不被并发修改”,还是“一个端口不被重复监听”,前者靠文件锁就行,后者得换 net.Listen 的地址复用控制。










