C++如何对正在打开的文件加文件锁(flock/LockFile)

轻雪君_4570

轻雪君_4570

2026-10-20

712人浏览

原创

flock是对整个文件施加的建议性锁,与文件描述符绑定,通过close()自动释放,不支持字节范围锁定,且在nfsv3等文件系统上不可用。

c++如何对正在打开的文件加文件锁(flock/lockfile)

Linux 下用 flock 对已打开的文件描述符加锁

只要文件描述符是通过 open() 获得的(且未被 dup() 或 fork() 复制导致语义混淆),flock() 就能直接作用于它。它不关心文件是否“正在被打开”,只关心 fd 是否有效、是否指向一个支持 flock 的文件系统(如 ext4、XFS;不支持 NFSv3 及更早版本)。

常见错误是试图对 stdin/stdout 或管道 fd 调用 flock,会返回 EBADF;另一个坑是没检查返回值——flock(fd, LOCK_EX) 阻塞时看似卡住,其实是正常行为,但若传入了 LOCK_NB 却忽略 EWOULDBLOCK,就会误判为失败。

  • flock() 是建议性锁(advisory),所有协作进程必须主动调用才能生效,内核不强制拦截读写
  • 锁与 fd 绑定,close(fd) 会自动释放锁;dup(fd) 不增加锁计数,但两个 fd 都 close 后锁才释放
  • 避免在多线程中混用同一 fd:flock 锁的是文件,不是线程,但多个线程对同一 fd 并发调用 flock 可能因竞态导致逻辑混乱

Windows 下用 LockFile 锁住已映射或已打开的句柄

Windows 的 LockFile(及其带超时的变体 LockFileEx)要求句柄必须以 FILE_SHARE_READ 和/或 FILE_SHARE_WRITE 打开,且不能是控制台句柄、标准流句柄或某些设备句柄。它锁的是文件偏移区间,不是整个文件——这点和 flock 本质不同。

典型错误是传入由 fopen() 得到的 FILE*,必须先用 _get_osfhandle() 转成 HANDLE;另一个常见疏漏是没处理重叠 I/O 场景:LockFileEx 在异步模式下需配合 OVERLAPPED 结构,否则调用会失败并返回 ERROR_INVALID_PARAMETER。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
  • LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF) 表示锁定整个文件(4GB × 4GB 区域,覆盖 32 位偏移全范围)
  • 锁是强制性的(mandatory),但仅当卷启用了“强制锁定”策略(fsutil behavior set disablelastaccess 1 不相关,真正开关是 fsutil behavior set lockvolume 1,且需 NTFS 格式)
  • 锁不会随 CloseHandle() 自动释放?错——会释放。但若进程异常终止,系统会回收句柄并释放锁,无需手动清理

跨平台封装时为什么别直接封装 flock 和 LockFile

二者语义差异太大:flock 是 fd 级、整文件、建议性、继承性锁;LockFile 是 HANDLE 级、字节区间、可强制、不可继承(默认)。强行统一接口容易掩盖行为差异,比如在 Windows 上用 flock-like 接口调用 LockFileEx 时忽略 lpOverlapped,会导致同步锁行为在高并发下卡死或失败。

更稳妥的做法是分层:底层保留原生调用,上层按使用场景抽象——例如日志模块需要“独占写入”,就封装为 acquire_log_writer_lock(),内部根据平台选 flock(fd, LOCK_EX) 或 LockFileEx(h, LOCKFILE_EXCLUSIVE_LOCK, ...);而数据库 WAL 日志可能需要区间锁,则直接暴露平台原生接口,不强行抹平。

  • 不要假设 flock 在 NFS 上可用——它在 NFSv4 默认启用,但 v3 基本无效;LockFile 在 SMB 共享上也受限,需确认服务器支持 byte-range locking
  • C++ RAII 封装锁时,析构函数里调用 close() 或 CloseHandle() 即可释放,无需额外 unlock 调用(flock 没 unlock 函数,UnlockFile 是可选的,close 已足够)
  • 测试时务必覆盖进程崩溃场景:用 kill -9 或 Windows 任务管理器结束进程,验证锁是否如期释放

为什么 std::fstream 无法直接加锁

因为 std::fstream 封装的是 C++ 流抽象,其底层 HANDLE 或 fd 对用户不可见,且标准库未提供任何锁接口。试图对 std::fstream::rdbuf()->pubseekoff() 后调用 flock 会失败——你拿不到它的 fd;Windows 下用 _get_osfhandle(_fileno(fstream.rdbuf()->_file())) 也不可靠,因某些实现可能缓冲或复用句柄。

正确做法是绕过流对象,用原始系统调用打开文件,再把 fd/HANDLE 传给 flock 或 LockFile。如果必须用 std::fstream 读写,应在加锁后,用 fdopen()(Linux)或 _fdopen()(Windows)桥接,但要注意:C++ 流的缓冲行为可能导致写入延迟,锁住的只是“打开动作”,不是“数据落盘时机”。

  • Linux 示例:int fd = open("log.txt", O_RDWR | O_CREAT, 0644); flock(fd, LOCK_EX); FILE* fp = fdopen(fd, "a"); —— 此时 fp 写入受锁保护,但需注意 fflush(fp) 确保立即落盘
  • Windows 示例:HANDLE h = CreateFile(L"log.txt", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); LockFileEx(h, LOCKFILE_EXCLUSIVE_LOCK, 0, 0xFFFFFFFF, 0xFFFFFFFF, &overlapped);
  • 最易忽略的一点:锁只防止其他进程修改文件内容,不保证你自己的多个线程对同一 std::fstream 的并发 write 是线程安全的——那属于流对象内部状态竞争,和文件锁无关

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.14

2248

9

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

1019

6

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

427

5

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

327

5

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

406

5

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

580

5

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.21

1409

9

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

2024.03.22

1217

7

c++和c语言学习顺序推荐
c++和c语言学习顺序推荐

对于初学者,建议先学习C语言,掌握编程基础后再转入C++,便于理解面向对象编程概念。有编程经验者可直接学习C++,快速接触高级编程技术。想了解更多c++和c语言的相关内容,可以阅读本专题下面的文章。

2024.03.25

1325

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习