bigywater.tech
Rust · 148

文件锁

想保证同一时刻只有一个进程在改某个文件,怎么办?这篇用标准库自带的文件锁 API,在真实的多进程场景下验证独占与共享、阻塞与非阻塞、崩溃后的释放,以及「建议性」到底意味着什么。

WouldBlock
另一个进程持有独占锁时 try_lock 的结果
0 次清理
kill -9 持有者之后需要手动清理锁的次数(自动释放)
建议性
不加锁的进程仍然可以写被锁定的文件

独占锁与阻塞

实测 · 本机执行输出
  try_lock(独占):WouldBlock(被别人持有)
  try_lock_shared(共享):WouldBlock(被别人持有)
  lock(独占)阻塞了约 600 ms 才拿到(持有者睡 600 ms 后退出,实际等待 604 ms)

文件基础见std::fs 文件读写;子进程见子进程与 Command。

共享锁

实测 · 本机执行输出
  try_lock_shared(共享):拿到
  try_lock(独占):WouldBlock(被别人持有)

进程崩溃

实测 · 本机执行输出
  持有者运行中:try_lock(独占):WouldBlock(被别人持有)
  kill -9 持有者之后:try_lock(独占):拿到

建议性锁

实测 · 本机执行输出
  持有独占锁期间,另一个进程 没有加锁直接写文件:成功(锁是建议性的)
  文件内容:'written without taking the lock'

同一个进程里

实测 · 本机执行输出
  句柄 a 拿到独占锁
  同一进程里的句柄 b try_lock:WouldBlock
  句柄 a 再 try_lock 一次(已经持有):成功(幂等)
  a.unlock() 之后 b try_lock:拿到
  b 被 drop(关闭文件)时锁也随之释放:再开一个句柄 c 能拿到锁:true

文件描述符的释放见文件描述符与资源释放。

分步演示

文件锁
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动
    • 没有验证:NFS 等网络文件系统上的锁行为、Windows 的强制锁语义、fcntl 记录锁(按字节范围)、fork 之后子进程继承锁的情况、死锁检测(标准库不提供)、锁升级与降级
    京ICP备2026067502号-1京公网安备11010502063487号