在读取和写是原子的

在读取和写是原子的

本文介绍了应该 LOCK_EX 在读取和写是原子的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

file_put_contents ( "file", "data", LOCK_EX )

用于写入(这意味着 - 获取锁定和写入)

for writing (which means - aquire lock and write)

file_get_contents ( "file", LOCK_EX )

用于读取(即 - 获取锁然后读取)

for reading (which means - aquire lock and then read)

会抛出异常吗?引发错误?阻塞直到获得锁?或者至少 - 应该?php 有没有可能有一天会变成这样?

will it throw exception? raise an error? block until lock is aquired?or at least - should it? is there a chance that php will behave like this one day?

我知道可以使用重命名 - 我想知道答案...

i know that it is possible to use rename - i'd like to know answer to this...

推荐答案

由于这个答案很长,这里是总结:不,file_get_contents() 不是原子的,因为它不尊重咨询锁.

Since this answer is long, here's the summary: No, file_get_contents() is not atomic as it does not respect advisory locks.

在 PHP 中,在 *nix 平台上,文件系统锁定只是建议性的.根据文档(重点是我的):

In PHP, while on a *nix platform, filesystem locking is advisory only. Per the docs (Emphasis mine):

PHP 支持一种以咨询方式锁定完整文件的可移植方式(这意味着所有访问程序必须使用相同的锁定方式,否则将无法工作).默认情况下,此函数将阻塞,直到获得请求的锁;这可以通过下面记录的 LOCK_NB 选项来控制(在非 Windows 平台上).

因此,只要访问文件的所有进程都使用这种锁定方法,就可以了.

So, as long as all of the processes that are accessing the file use this method of locking, you're fine.

但是,如果您正在使用健全的网络服务器编写静态 HTML 文件,则锁定将被忽略.在写入过程中,如果有请求进来,Apache 将提供部分写入的文件.锁对读取锁的其他进程没有影响.

However, if you're writing a static HTML file with a sane webserver, the lock will be ignored. In the middle of the write, if a request comes in, Apache will serve the partially written file. The locks will have no effect on the other process reading the lock.

唯一真正的例外是,如果您在文件系统上使用 -o mand 的特殊挂载选项来启用强制锁定(但这并没有真正使用多少,并且可能会降低性能).

The only real exception is if you use the special mount option of -o mand on the filesystem to enable mandatory locking (but that's not really used much, and can have a performance penalty).

阅读文件锁定以了解更多信息.即Unix下的部分:

Have a read on File Locking for some more information. Namely the section under Unix:

这意味着协作进程可以使用锁来协调它们之间对文件的访问,但程序也可以随意忽略锁并以它们选择的任何方式访问文件.

所以,总而言之,使用 LOCK_EX 将在文件上创建一个咨询锁.仅当读取器尊重和/或检查锁定时,任何读取文件的尝试才会被阻止.如果他们不这样做,锁将被忽略(因为它可以).

So, in conclusion, using LOCK_EX will create an advisory lock on the file. Any attempt to read the file will block only if the reader respects and/or checks for the lock. If they do not, the lock will be ignored (since it can be).

试试看.在一个过程中:

Try it out. In one process:

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);

当它在睡觉时,调用这个:

And while it's sleeping, call this:

$f = fopen('test.txt', 'a+');
fwrite($f, 'foobar');
fclose($f);

输出将是 foobar...

对于您的其他具体问题,首先,.所以你不能把它传进去.

To your other specific question, first off, there is no LOCK_EX parameter to file_get_contents. So you can't pass that in.

现在,查看源代码,我们可以看到第 521 行定义的函数 file_get_contents.没有调用内部函数 php_stream_lock,因为当你传递 file_put_contents('file', 'txt', LOCK_EX); 定义在同一个文件的第 589 行.

Now, looking at the source code, we can see the function file_get_contents defined on line 521. There are no calls to the internal function php_stream_lock as there are when you pass file_put_contents('file', 'txt', LOCK_EX); defined on line 589 of the same file.

那么,让我们测试一下吧:

So, let's test it, shall we:

在 file1.php 中:

In 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);

在 file2.php 中:

In file2.php:

var_dump(file_get_contents('test.txt'));

运行时,file2.php 立即返回.所以不,file_get_contents 似乎根本不尊重文件锁......

When run, file2.php returns immediately. So no, it doesn't appear that file_get_contents respects file locks at all...

这篇关于应该 LOCK_EX 在读取和写是原子的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 19:04