flock仅Linux/macOS可用,Windows无系统调用支持;lockf虽POSIX但语义不同且Windows不支持;跨平台应优先用boost::interprocess::file_lock或std::filesystem原子操作实现锁文件协议。

flock 在 Linux/macOS 上能用,Windows 上直接报错
Linux 和 macOS 的 flock 是基于文件描述符的 advisory 锁,轻量、简单、支持进程间协作。但 Windows 根本没有 flock 系统调用,glibc 或 musl 里也没有模拟实现——你如果在跨平台代码里直接调 flock(),Windows 下连编译都过不去(error: 'flock' was not declared in this scope)。别指望宏定义 #ifdef 能绕过去,底层语义不一致,硬套只会埋坑。
实操建议:
- 不要尝试封装一个“统一接口”假装
flock全平台可用;语义差异太大,比如flock锁随 fd 关闭自动释放,而 Windows 的LockFileEx必须显式UnlockFileEx - 若只跑 Linux/macOS,放心用
flock(),注意它锁的是“打开的文件对象”,不是路径——两个进程 open 同一路径得到不同 fd,flock不会互斥 - Windows 替代方案只能是
CreateFile+LockFileEx,或更上层的std::filesystem::create_directories配合原子 rename(仅限某些场景)
lockf 是 POSIX 的,但行为和 flock 不一样
lockf() 看似更“标准”,但它本质是 fcntl(F_SETLK) 的包装,锁粒度是字节范围,且默认是 advisory 锁(不强制拦截读写),和 flock 的整个文件锁语义不同。更重要的是:Windows 官方头文件里压根没声明 lockf,MinGW-w64 虽然提供了 stub,但实际调用会返回 -1 并设 errno = ENOSYS。
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 代码里写
lockf(fd, F_LOCK, 0),Linux 下正常,Windows 下静默失败(返回 -1 但没检查),结果锁根本没生效 - 误以为
lockf和flock可互换,结果在多线程+多进程混合场景下出现竞态:一个进程用flock锁了文件,另一个用lockf还能成功加锁(advisory 锁不互通) -
lockf的锁会被 fork 继承,且子进程退出不自动释放——容易漏 unlock 导致死锁
真正跨平台的最小可行方案:用 std::filesystem + 原子操作兜底
C++17 的 std::filesystem 提供了有限但可用的跨平台原语:std::filesystem::create_directory 是原子的(失败即说明已被抢占),配合临时文件 + std::filesystem::rename(POSIX rename 和 Windows MoveFileEx 都是原子的),可以构造出进程间互斥的“锁文件”协议。
使用场景:不需要实时响应、允许短时轮询、锁持有时间不长(如配置写入、单次初始化)。
实操建议:
- 约定锁文件路径为
data.lock,尝试创建同名目录(非文件):std::filesystem::create_directory("data.lock") - 成功 → 拿到锁;失败(
std::filesystem::exists("data.lock") == true)→ 等待后重试 - 用完后
std::filesystem::remove("data.lock")—— 注意:Windows 下 remove 目录需确保无句柄打开,建议用空目录,避免残留 - 不适用于高频争抢或长时持有,因为轮询浪费 CPU,且无法阻塞等待
生产环境别自己手撸,优先用成熟的跨平台库
自己实现文件锁,99% 的情况是在重复造轮子,还容易漏掉 corner case:比如 NFS 挂载下的锁失效、容器内 PID namespace 导致的 pid 冲突、杀进程未清理锁文件等。
推荐方案:
-
boost::interprocess::file_lock:C++ 实现,封装了各平台原生 API(flock/fcntlon POSIX,LockFileExon Windows),自动处理 fd 生命周期和错误映射 - 若项目已用
libuv或Qt,直接用uv_fs_fstat+ 自定义逻辑,或QFile::lock()(后者在 Windows 下用LockFileEx,Linux 下 fallback 到flock) - 避免用
std::ofstream构造时加std::ios::ate之类“伪锁”——没任何同步保证,纯属心理安慰
最麻烦的点其实是锁的语义一致性:同一个锁,在 Linux 下可能被 fork 出的子进程继承,在 Windows 下则完全隔离。跨平台时,别只盯着“能不能加锁”,得想清楚“谁该看到这个锁、谁不该看到、意外崩溃后怎么恢复”。这些细节藏在系统文档角落里,不踩几次坑根本意识不到。



















