php 中与 flock 的文件访问同步

File access synchronization with flock in php

我正在尝试了解使用 PHP 中的 flock 同步文件 read/write 的正确方法。

我有两个 php 脚本。

testread.php:

<?
$fp=fopen("test.txt","r");
if (!flock($fp,LOCK_SH))
  echo "failed to lock\n";
else
  echo "lock ok\n";
while(true) sleep(1000);

?>

和testwrite.php:

<?
$fp=fopen("test.txt","w");
if (flock($fp,LOCK_EX|LOCK_NB))
{
  echo "acquired write lock\n";
}
else
{
  echo "failed to acquire write lock\n";
}
fclose($fp);
?>

现在我 运行 testread.php 让它挂在那里。然后我 运行 testwrite.php 在另一个会话中。正如预期的那样,flock 在 testwrite.php 中失败了。但是,当 testwrite.php 退出时,文件 test.txt 的内容被清除。事实上,即使文件已在另一个进程中锁定,fopen 也总是会成功。如果文件以 "w" 模式打开,无论锁定如何,文件内容都将被删除。那么这里的 flock 有什么意义呢?它并没有真正保护任何东西。

您正在 testwrite.php 中以 w 模式使用 fopen()。当使用 w 选项时,fopen() 将在打开文件后截断文件。 (参见 fopen())。

因此,在您尝试获取独占锁之前,文件在您的示例中被截断了。但是你需要一个打开的文件描述符才能使用 flock().

摆脱这种困境的方法是使用与您正在处理的文件不同的锁定文件。 flock() 手册页提到了这一点:

Because flock() requires a file pointer, you may have to use a special lock file to protect access to a file that you intend to truncate by opening it in write mode (with a "w" or "w+" argument to fopen()).

接受的答案过于复杂。您可以简单地使用 "c" 参数打开文件,这不会截断文件。然后只有在获得锁时才调用 ftruncate()。

来自documentation

'c' Open the file for writing only. If the file does not exist, it is created. If it exists, it is neither truncated (as opposed to 'w'), nor the call to this function fails (as is the case with 'x'). The file pointer is positioned on the beginning of the file. This may be useful if it's desired to get an advisory lock (see flock()) before attempting to modify the file, as using 'w' could truncate the file before the lock was obtained (if truncation is desired, ftruncate() can be used after the lock is requested).