Windows用CreateFile+LockFileEx实现排他锁,需设LOCKFILE_EXCLUSIVE_LOCK和LOCKFILE_FAIL_IMMEDIATELY;Unix应选fcntl而非flock,因其fd粒度、支持NFS且读写锁分离;跨平台封装须独占管理锁状态、校验权限并覆盖NFS等场景。

Windows下用CreateFile和LockFileEx实现排他锁
Windows原生不支持POSIX风格的flock,必须用WinAPI。关键不是打开文件,而是后续调用LockFileEx——它支持重叠I/O、超时和共享/独占模式。常见错误是忽略dwFlags参数:LOCKFILE_EXCLUSIVE_LOCK才表示写锁,LOCKFILE_FAIL_IMMEDIATELY能避免阻塞,否则默认会挂起线程。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用
GENERIC_READ | GENERIC_WRITE和FILE_SHARE_NONE打开文件,否则其他进程可能绕过锁 -
LockFileEx的lpOverlapped可传nullptr,但若设超时(如INFINITE),必须确保句柄是异步创建的(FILE_FLAG_OVERLAPPED) - 解锁必须显式调用
UnlockFileEx;进程退出时系统自动释放,但不可依赖——异常路径下容易漏掉
Linux/macOS用flock还是fcntl?选fcntl
flock简单但有严重缺陷:它基于进程而非文件描述符,且在NFS上基本失效;fcntl的F_SETLK才是可靠选择。它操作的是fd粒度,支持读写锁分离,且兼容NFS(只要服务端支持)。错误现象常是flock在容器或网络文件系统里“看起来生效但实际不互斥”。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用
open(..., O_RDWR)获取fd,O_RDONLY无法加写锁 -
struct flock中l_type设F_WRLCK或F_RDLCK,l_whence = SEEK_SET,l_start = l_len = 0锁整个文件 - 检查返回值:失败时
errno == EAGAIN表示被占用,errno == EDEADLK说明检测到死锁(极少见但需处理)
跨平台封装的关键:抽象出统一的锁生命周期
不能简单把两套API塞进一个类接口,核心矛盾在于语义差异:Windows锁绑定句柄,Unix锁绑定fd,而C++对象析构时机不确定。直接在析构函数里解锁风险很高——比如复制了std::shared_ptr指向该对象,多个副本析构时重复解锁会崩溃。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 锁状态必须由RAII对象独占管理,内部用
std::unique_ptr持有资源(Windows用HANDLE,Unix用int),禁止拷贝,只允许移动 - 提供
try_lock()和lock_or_timeout(int ms),避免用户自己处理INFINITE或EAGAIN循环 - Windows下
CloseHandle前必须UnlockFileEx,Unix下close自动释放锁——这点差异必须封装干净,用户不应感知
实际使用中最容易被忽略的点:锁文件路径和权限
跨平台时路径分隔符(/ vs \)只是表象,真正坑的是权限模型。Windows对文件锁无权限要求,但Linux要求进程对文件有读/写权限才能调用fcntl;如果文件属主是root且权限为600,普通用户进程即使能open成功,fcntl也会返回EPERM。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 构造锁对象前先做
access(path, W_OK)(Unix)或GetFileAttributes(Windows)校验可写性 - 不要锁目录——
flock和LockFileEx都不支持,有些实现会静默失败 - 测试必须覆盖NFS和本地ext4/APFS,尤其注意Docker容器内挂载卷时的锁行为是否一致
跨平台文件锁真正难的不是API调用,而是让锁在任意挂载方式、任意用户权限、任意进程生存周期下都保持语义一致。多数问题出在假设“锁住了就万事大吉”,其实释放时机、路径解析、错误传播链才是高频雷区。

















