php文件锁机制怎用改_php文件锁机制使用修改法【互斥】

1次阅读

php文件锁用flock()实现互斥写入,需先fopen()再flock(LOCK_EX),所有IO必须经该文件指针,file_put_contents的LOCK_EX仅保证单次写入原子性,无法保护“读-改-写”多步操作。

php文件锁机制怎用改_php文件锁机制使用修改法【互斥】

PHP 文件锁怎么实现互斥写入

flock() 最直接,但必须注意它默认是阻塞的,且只对同一文件句柄有效——不是“全局锁”,而是“当前进程+当前打开的文件流”级别的协作式锁。

  • 必须先用 fopen() 打开文件(哪怕只是 'r' 模式),再调用 flock(),不能对路径字符串直接加锁
  • 加锁后所有读写操作都得通过该文件指针进行,file_put_contents($path, $data) 这类函数会绕过锁,导致失效
  • 解锁靠 flock($fp, LOCK_UN) 或脚本结束时自动释放(但别依赖自动释放,尤其在 long-running 进程中)

flock() 的 LOCK_EX 和 LOCK_SH 区别在哪

LOCK_EX 是排他锁(写锁),同一时间只允许一个进程持有;LOCK_SH 是共享锁(读锁),多个进程可同时持有,但只要有 LOCK_EX 在,LOCK_SH 就会阻塞。

  • 想保证写入不被并发覆盖 → 用 LOCK_EX
  • 只是读取、又希望避免读到写到一半的脏数据 → 可配合 LOCK_SH,但需写方也主动用 LOCK_EX,否则读锁没意义
  • 加锁失败时 flock() 返回 false,不是抛异常,记得判断

为什么 file_put_contents(…, LOCK_EX) 不够用

file_put_contents($path, $data, LOCK_EX) 确实会内部调用 flock(),但它只锁住“这次写入”的瞬间:打开→加锁→写入→关闭。整个过程极短,无法覆盖“读-改-写”这类多步操作。

  • 比如:读出 jsON → 解码 → 修改某个字段 → 编码 → 写回。这四步之间没有锁保护,其他进程可能在中间插入写入
  • 这种场景必须手动用 fopen()+flock()+fwrite()+fclose() 把整段逻辑包住
  • LOCK_EX 标志位对 file_put_contents() 是“一次性原子写”,不是“会话级锁”

文件锁失效的常见坑

最典型的是 NFS 或某些容器挂载卷上 flock() 不生效——因为 POSIX 文件锁在部分网络文件系统上被禁用或模拟不完整。

立即学习PHP免费学习笔记(深入)”;

  • 测试方法:起两个终端,分别运行带 flock() 的脚本,看是否真能互斥
  • linux 下可通过 strace -e trace=flock php script.php 确认系统调用是否成功
  • 如果环境不可靠,得降级用目录锁(mkdir() 原子性)或外部服务(redis SETNX)

文件锁的“互斥”完全依赖协作,没人强制你加锁;而一旦涉及跨存储、跨语言或长事务,它的边界就很容易被忽略。

text=ZqhQzanResources