共享锁,独占锁和数据损坏

时间:2013-02-23 13:58:45

标签: php locking corrupt

我的问题是:期间不能共享锁会导致错误,即使写操作使用独家锁?

假设我想创建一个基于文件的计数器,如下所示:

//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。

我将代码更改为使用fopenLOCK_SH,现在似乎没问题,但我无法确认这确实是问题的根源,因为我无法控制负载。使用多个CLI PHP实例在本地执行上述代码表明代码甚至可以用file_get_contents ...

工作

2 个答案:

答案 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上的锁定文件根本不起作用。