flock(LOCK_SH / LOCK_EX)时,PHP脚本文件会无限期加载到浏览器中

时间:2018-11-15 03:40:03

标签: php fopen file-get-contents file-put-contents

我在尝试学习如何锁定文件以防止脚本在另一个文件写入时读取文件或两个脚本同时写入同一文件时遇到了这个link

我创建了两个脚本readandwritelock.phpreadlock.php,这是第一个脚本,用于检索带有file_get_contents的文件,追加它,然后使用file_put_contents($file, $data, LOCK_EX)写回到同一文件,而第二个文件仅在file_get_contents之后使用flock($file, LOCK_SH)检索文件。

<?php
    //readandwritelock.php

    $myfile = fopen('15-11-2018.txt', 'r+');
    if (flock($myfile, LOCK_SH)) {

        echo "Gotten lock<br>";
        $current = file_get_contents('15-11-2018.txt');

        /*I commented this on my second test to see if file_put_contents will work.
        After uncommenting and third test, it does not work anymore.

        if (flock($myfile, LOCK_UN)) {

            echo "Unlocked<br>";
        }*/

        $current .= "appending";

        if (file_put_contents('15-11-2018.txt', $current, LOCK_EX)) {
            echo "Success";
        }
        else {
            echo "Failed";
            //browser loads indefinitely so this does not run
        }

        fclose($myfile);
    }
?>

我面临的问题是,我第一次尝试获得锁后file_get_contents,然后释放锁并继续追加和file_put_contents($file, $data, LOCK_EX)。但是,在第二次尝试时,我决定评论释放LOCK_SH锁以进行测试,看看会发生什么。该脚本文件在浏览器中无限期加载(正在等待localhost ...),因此我第三次尝试恢复了所做的更改,但是这次脚本文件仍然无限期加载。好像从未发布过LOCK_SH

我肯定做错了什么,但我不知道它到底是什么。有人可以解释吗?

这已在XAMPP和macOS High Sierra和Chrome上进行了测试。

<?php
    //readlock.php
    //works as normal
    $myfile = fopen('15-11-2018.txt', 'r');

    if (flock($myfile, LOCK_SH)) {

        echo "Gotten lock<br>";
        $current = file_get_contents('15-11-2018.txt');
        echo $current;

        if (flock($myfile, LOCK_UN)) {
            echo "<br>Unlocked";
        }
        fclose($myfile);
    }
?>

1 个答案:

答案 0 :(得分:0)

浏览器似乎无限期加载的原因是因为您的PHP文件从未完成。

首先,您将获得文件的LOCK_SH(共享或读取锁定),这在读取内容时很好。 问题是您还尝试在file_put_contents函数中的同一文件上获得LOCK_EX(排他锁)。因此,file_put_contents函数将一直阻塞,直到所有其他锁(共享和独占锁)都被解锁为止,这是行不通的(这是一个死锁)。

为使代码正常运行,您可以尝试先获取排他锁

if( flock($myfile, LOCK_EX) ) {
    // ...

或者您在写之前解锁共享锁

flock($myfile, LOCK_UN);
if ( file_put_contents('15-11-2018.txt', $current, LOCK_EX) ) {
    // ...

通常,保持锁寿命尽可能短是一个好主意。如果您打算在读写之间对数据进行大量操作,建议您在读取后立即解锁文件,然后再次锁定以进行写入。