我的问题是:读期间不能共享锁会导致写错误,即使写操作是使用独家锁?
假设我想创建一个基于文件的计数器,如下所示:
//increment counter by 1
$fp = fopen($path, 'r+b');
if (flock($fp, LOCK_EX)) {
//read
fseek($fp, 0, SEEK_END);
$size = ftell($fp);
fseek($fp, 0, SEEK_SET);
if ($size == 0) {
$counter = 0;
} else {
$data = fread($fp, $size);
$counter = intval($data);
}
//do something with data we just read
$counter ++;
//write
fseek($fp, 0, SEEK_SET);
ftruncate($fp, 0);
fwrite($fp, $counter);
fflush($fp);
flock($fp, LOCK_UN);
fclose($fp);
} else {
fclose($fp);
throw new Exception("Lock failed");
}
现在我想把它呈现在其他地方:
echo intval(file_get_contents($path));
请注意,file_get_contents
不使用共享锁。
此代码已经证明在重页加载时会破坏数据,即计数器重置几次回到0。
我将代码更改为使用fopen
和LOCK_SH
,现在似乎没问题,但我无法确认这确实是问题的根源,因为我无法控制负载。使用多个CLI PHP实例在本地执行上述代码表明代码甚至可以用file_get_contents
...
答案 0 :(得分:0)
ftell手册中的注释讨论了使用追加模式打开的文件的不可预测行为。也许您可以尝试以只读方式打开文件进行读取,或者只是读取文件,我不明白为什么在代码中有一行可以明确地将计数器设置为0。
echo intval(false); //0
对EOF的畏惧返回false,所以:
$fp = fopen($path, 'r+b');
if (flock($fp, LOCK_EX)) {
//read
$data = fread($fp, $size);
$counter = intval($data);
//do something with data we just read
$counter ++;
//write
fseek($fp, 0, SEEK_SET);
ftruncate($fp, 0);
fwrite($fp, $counter);
fflush($fp);
flock($fp, LOCK_UN);
fclose($fp);
} else {
fclose($fp);
throw new Exception("Lock failed");
}
答案 1 :(得分:0)
flock
功能,不幸的是我们无法改变它。我想我必须实现自定义锁定机制。
这是因为生产服务器具有NFS文件系统,并且在大多数情况下NFS上的锁定文件根本不起作用。