windows用createfile设dwsharemode=0可拒绝其他进程读写,linux用flock实现建议锁,跨平台应避免硬封装而采用.lock文件等外部协调机制。

Windows 下用 CreateFile 配合共享模式锁文件
Windows 本身不提供“独占写入锁”的原子语义,但可通过 CreateFile 的 dwShareMode 参数拒绝其他进程以冲突方式打开该文件。关键不是“加锁”,而是“拒绝共享”。
常见错误是只传 0 或漏设 FILE_SHARE_READ/FILE_SHARE_WRITE,导致后续打开失败或锁失效。
- 要完全阻止其他进程读写:调用
CreateFile时传dwShareMode = 0(即不共享) - 若允许别人只读:用
FILE_SHARE_READ,但此时别人仍可OpenFile读,只是不能写 - 句柄必须保持打开状态——关闭后锁立即释放,没有“后台持续锁”这回事
- 注意:仅对通过 Win32 API 打开文件的行为有效;映射文件(
CreateFileMapping)或某些备份工具可能绕过
Linux/macOS 用 flock 是最轻量的协作式锁
flock 是基于文件描述符的 advisory lock(建议性锁),不阻塞底层 I/O,依赖所有参与者主动检查。它简单、无状态、不依赖文件系统类型,适合进程间协调。
典型误用是忘记检查返回值,或在 fork 后未处理子进程继承的 fd 导致锁意外释放。
- 加锁前必须先
open文件获取 fd,再调用flock(fd, LOCK_EX) - 锁随 fd 关闭自动释放——
close(fd)或进程退出都会释放,不要靠LOCK_UN显式解锁(易遗漏) - 多个进程对同一文件调用
flock会阻塞或失败(取决于是否传LOCK_NB),但不会影响已打开的 fd 的读写能力 - 不适用于 NFS(部分实现不支持),且无法防止非
flock方式访问(如直接write到另一个 fd)
跨平台方案别硬套,优先用 std::fstream + 外部机制
C++ 标准库不提供文件锁接口,std::fstream 打开文件时既不加锁也不检查锁。所谓“C++ 锁文件”本质是调用平台 API 封装,不存在纯标准解法。
强行封装跨平台锁容易掩盖行为差异,比如 Windows 的强制锁和 Linux 的建议锁语义完全不同,混用会导致逻辑错乱。
- 若需跨平台,推荐在业务层引入外部协调机制:如写入前创建同名
.lock临时文件(配合open(..., O_CREAT | O_EXCL)或CreateFile(..., CREATE_NEW)) - 避免用
std::ofstream直接覆盖原文件——应写新文件 +rename原子替换,降低被并发修改的窗口期 - 日志类场景慎用锁:高频写入下锁竞争严重,不如用单进程写入 + ring buffer 或日志轮转
为什么 LockFileEx 和 fcntl(F_SETLK) 容易踩坑
这两个是更底层的锁接口,支持字节范围锁和异步/重叠锁,但复杂度陡增,90% 的需求根本用不到。
新手常以为它们“更可靠”,实际反而更容易出问题:比如 Windows 上 LockFileEx 要求文件句柄必须以 FILE_FLAG_OVERLAPPED 创建,否则失败却不报错;Linux 上 fcntl 对普通文件锁在 close 后失效,但对 NFS 可能 hang 住。
-
LockFileEx的lpOverlapped参数若为nullptr,会变成同步阻塞调用,且不兼容所有文件系统(如 ReFS) -
fcntl(F_SETLK)在 Linux 上对符号链接、挂载点、procfs 文件等无效,且锁信息不跨 mount namespace - 两种锁都不保证磁盘一致性——锁住文件 ≠ 锁住缓存页,
fsync仍需显式调用
真正需要字节级控制或超时等待时才考虑它们,否则用 flock 或 CreateFile 共享模式更稳。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











