std::ofstream不提供文件锁,加std::mutex无法解决跨进程竞态;linux下flock()失败主因是先构造ofstream再取fd,应反向用open→flock→fdopen;windows下lockfileex()要求重叠句柄,需createfile显式指定file_flag_overlapped。

std::ofstream 本身不提供文件锁,加 std::mutex 也拦不住其他进程——失败根本不是线程问题,是跨进程竞态。
flock() 在 Linux 下为什么调用失败
常见错误是:先构造 std::ofstream,再试图对它的内部 fd 加 flock()。但 std::ofstream 不暴露 fd,且其底层句柄可能已关闭或不可控,flock() 必然失败(返回 -1,errno 常为 EBADF)。
- 正确路径必须反着来:用
open()拿到原始 fd → 调用flock(fd, LOCK_EX)→ 再用fdopen()包装成FILE*→ 最后通过std::ostream构造函数绑定(C++11+ 支持) - 更稳妥的做法是绕过流类,直接用
write()+fsync(),避免流缓冲与锁生命周期错位 - 注意
flock()是建议锁:它只在所有参与者都主动调用时才生效;它不阻止open()或write(),只在你显式flock()时阻塞
Windows 上 LockFileEx() 失败的典型原因
最常踩的坑是:直接对 std::ofstream 的句柄调用 LockFileEx(),结果失败,GetLastError() 返回 ERROR_NOT_SUPPORTED。
- 根本原因是:
std::ofstream默认以非重叠(FILE_FLAG_OVERLAPPED未设)方式打开文件,而LockFileEx()强制要求重叠句柄 - 正确做法:必须用
CreateFile()显式传入FILE_FLAG_OVERLAPPED→ 得到HANDLE→ 调用LockFileEx()→ 用_open_osfhandle()转成 CRT fd → 再用_fdopen()套成FILE* - 若坚持用
std::ofstream,只能放弃字节级锁,改用命名互斥体(CreateMutex()),但它只保“单写者”,不保写操作原子性——仍需配合临时文件 +MoveFileEx()
多线程 + 多进程混合场景下锁失败的根源
你以为加了 std::mutex 就安全了?其实只是把多个线程串行化进同一个临界区,但每个进程都有自己的 std::mutex 实例,完全不互通。
- 现象:两个进程同时运行,日志内容交叉、截断、丢失——这不是 bug,是设计缺陷
- 关键区分:线程同步(
std::mutex/std::shared_mutex)解决的是进程内资源竞争;文件锁(flock()/LockFileEx())解决的是进程间文件访问冲突 - 混合使用时,务必分层:进程内用
std::mutex控制写入顺序;进程间用系统级锁控制文件访问;二者不能互相替代
真正容易被忽略的是锁粒度和错误恢复:flock() 锁整个文件,fcntl() 可锁任意区域,但 Windows 的 LockFileEx() 要求偏移对齐;另外,任何锁调用失败后,必须检查是否已部分写入,并决定是否回滚或重试——这点在日志、配置写入等场景里,往往比锁本身更致命。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











