php文件锁用flock()实现互斥写入,需先fopen()再flock(lock_ex),所有io必须经该文件指针,file_put_contents的lock_ex仅保证单次写入原子性,无法保护“读-改-写”多步操作。
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(),但它只锁住“这次写入”的瞬间:打开→加锁→写入→关闭。整个过程极短,无法覆盖“读-改-写”这类多步操作。