Kam*_*šík 21 php locking atomic blocking atomicity
file_put_contents ( "file", "data", LOCK_EX )
Run Code Online (Sandbox Code Playgroud)
写作(意思是 - 获取锁定和写入)
file_get_contents ( "file", LOCK_EX )
Run Code Online (Sandbox Code Playgroud)
用于阅读(这意味着 - 获取锁定然后阅读)
它会抛出异常吗?提出错误?阻止直到获得锁定?或者至少 - 应该吗?有一天php会有这样的表现吗?
编辑:我知道可以使用重命名 - 我想知道答案...
irc*_*ell 42
由于这个答案很长,这里是摘要: 不,file_get_contents()不是原子的,因为它不尊重咨询锁.
在PHP中,在*nix平台上,文件系统锁定仅供参考.根据文档(强调我的):
PHP支持以咨询方式锁定完整文件的可移植方式(这意味着所有访问程序必须使用相同的锁定方式,否则将无法工作).默认情况下,此功能将阻止,直到获取所请求的锁定为止; 这可以通过下面记录的LOCK_NB选项进行控制(在非Windows平台上).
因此,只要访问该文件的所有进程都使用这种锁定方法,您就可以了.
但是,如果您使用理智的Web服务器编写静态HTML文件,则会忽略锁定.在写入过程中,如果有请求进入,Apache将提供部分写入的文件.锁定对读取锁定的其他进程没有影响.
唯一真正的例外是,如果您使用-o mand文件系统上的特殊挂载选项来启用强制锁定(但实际上并没有太多使用,并且可能会降低性能).
阅读文件锁定以获取更多信息.即Unix下的部分:
这意味着协作进程可以使用锁来协调对文件之间的访问,但是程序也可以自由地忽略锁并以他们选择的任何方式访问文件.
因此,总之,using LOCK_EX将在文件上创建一个咨询锁.只有在读者尊重和/或检查锁定时,才会阻止任何读取文件的尝试.如果他们不这样做,锁将被忽略(因为它可以).
试试看.在一个过程中:
file_put_contents('test.txt', 'Foo bar');
$f = fopen('test.txt', 'a+');
if (flock($f, LOCK_EX)) {
sleep(10);
fseek($f, 0);
var_dump(fgets($f, 4048));
flock($f, LOCK_UN);
}
fclose($f);
Run Code Online (Sandbox Code Playgroud)
在它睡觉的时候,打电话给:
$f = fopen('test.txt', 'a+');
fwrite($f, 'foobar');
fclose($f);
Run Code Online (Sandbox Code Playgroud)
输出将是foobar......
file_get_contents具体:对于您的其他具体问题,首先,没有LOCK_EX参数file_get_contents.所以你不能通过它.
现在,查看源代码,我们可以看到file_get_contents在第521行定义的函数.没有调用内部函数,php_stream_lock因为当你传递file_put_contents('file', 'txt', LOCK_EX);同一文件的第589行定义时.
那么,让我们测试一下,我们应该:
在file1.php中:
file_put_contents('test.txt', 'Foo bar');
$f = fopen('test.txt', 'a+');
if (flock($f, LOCK_EX)) {
sleep(10);
fseek($f, 0);
var_dump(fgets($f, 4048));
flock($f, LOCK_UN);
}
fclose($f);
Run Code Online (Sandbox Code Playgroud)
在file2.php中:
var_dump(file_get_contents('test.txt'));
Run Code Online (Sandbox Code Playgroud)
运行时,file2.php立即返回.所以不,它似乎根本不file_get_contents尊重文件锁...
程序员的理论问题比这里的要好得多。
此时,PHP 不支持原子文件锁定。
简而言之,PHP 不支持组合fopen和flock操作,因此在您的进程可以锁定它之前,另一个进程总是有一个小的机会锁定您的进程也打开的文件。
话虽如此,flock默认情况下会阻塞,直到锁被释放。不过,请记住 ircmaxell 关于 Linux/BSD 上的建议锁的说明。
注意:对于读取过程,您可能希望将其设为一个LOCK_SH而不是LOCK_EX,以便多个读取器线程可以同时锁定它。必须始终使用LOCK_EX或风险数据损坏来完成写入。
注 2:上一条说明有效,因为只有在不存在排他锁的情况下才能获取共享锁,但排他锁要求在获取锁之前不存在任何类型的锁。