为什么我无法阅读使用 LOCK_EX
锁定的文件?我仍然可以写信给它。
我想知道,如果一个进程锁定文件(使用LOCK_SH
或LOCK_EX
)并且另一个进程尝试读取此文件或写入该文件,则会发生什么,但忽略了锁定。所以我制作了一个有三个功能的小脚本:
我通过两个控制台并排进行测试并进行了以下操作:
FIRST CONSOLE | SECOND CONSOLE
-----------------------------+-----------------------
php test lock LOCK_SH | php test read
php test lock LOCK_SH | php test write
php test lock LOCK_EX | php test read
php test lock LOCK_EX | php test write
LOCK_SH
似乎完全没有效果,因为第一个进程以及第二个进程可以读取和写入文件。如果第一个进程使用LOCK_EX
锁定了文件,则两个进程仍然可以写入,但只有第一个进程可以读取。 这背后有什么理由吗?
这是我的小测试程序(在 Windows 7家庭高级版 64位上测试过):
<?php
// USAGE: php test [lock | read | write] [LOCK_SH | LOCK_EX]
// The first argument specifies whether
// this script should lock the file, read
// from it or write to it.
// The second argument is only used in lock-mode
// and specifies whether LOCK_SH or LOCK_EX
// should be used to lock the file
// Reads $file and logs information.
function r ($file) {
echo "Reading file\n";
if (($buffer = @fread($file, 64)) !== false)
echo "Read ", strlen($buffer), " bytes: ", $buffer, "\n";
else
echo "Could not read file\n";
}
// Sets the cursor to 0.
function resetCursor ($file) {
echo "Resetting cursor\n", @fseek($file, 0, SEEK_SET) === 0 ? "Reset cursor" : "Could not reset cursor", "\n";
}
// Writes $str to $file and logs information.
function w ($file, $str) {
echo "Writing \"", $str, "\"\n";
if (($bytes = @fwrite($file, $str)) !== false)
echo "Wrote ", $bytes, " bytes\n";
else
echo "Could not write to file\n";
}
// "ENTRYPOINT"
if (($file = @fopen("check", "a+")) !== false) {
echo "Opened file\n";
switch ($argv[1]) {
case "lock":
w($file, "1");
echo "Locking file\n";
if (@flock($file, constant($argv[2]))) {
echo "Locked file\n";
w($file, "2");
resetCursor($file);
r($file);
echo "Sleeping 10 seconds\n";
sleep(10);
echo "Woke up\n";
echo "Unlocking file\n", @flock($file, LOCK_UN) ? "Unlocked file" : "Could not unlock file", "\n";
} else {
echo "Could not lock file\n";
}
break;
case "read":
resetCursor($file);
r($file);
break;
case "write":
w($file, "3");
break;
}
echo "Closing file\n", @fclose($file) ? "Closed file" : "Could not close file", "\n";
} else {
echo "Could not open file\n";
}
?>
答案 0 :(得分:3)
这是一个非常好的问题,但也很复杂,因为它取决于很多条件。
我们必须从另一对锁定类型开始 - 建议和强制:
......这应该回答你的问题,但我会继续解释你的具体案例。
您似乎遇到的是咨询锁的行为 - 无论是否存在锁定或者您是否检查过文件,都无法阻止您读取或写入文件。<登记/> 但是,您会找到note in the PHP manual for flock(),说明以下内容:
flock()在Windows上使用强制锁定而不是建议锁定。通过fcntl()系统调用支持的常用机制,基于Linux和System V的操作系统也支持强制锁定:即,如果相关文件设置了setgid权限位并且组执行位已清除。在Linux上,还需要使用mand选项挂载文件系统,以使其正常工作。
因此,如果PHP在Windows上使用强制锁定并且您在Windows上对此进行了测试,则说明手册错误/过时/不准确(我现在懒得检查)或者你必须在同一页面上阅读这个大红色警告:
在某些操作系统上,flock()是在进程级别实现的。使用像ISAPI这样的多线程服务器API时,您可能无法依赖flock()来保护文件免受在同一服务器实例的并行线程中运行的其他PHP脚本的影响!
在FAT及其派生类等过时的文件系统上不支持flock(),因此在这种环境下总是会返回FALSE(对于Windows 98用户尤其如此)。
我不相信你的php-cli可执行文件甚至可能以某种方式为自己生成线程,所以你可以选择使用一个根本不存在的文件系统。支持锁定。
我的猜测是手册并不完全准确,事实上你确实在Windows上获得建议锁,因为你在LOCK_EX
之间也遇到了不同的行为(独家)锁定)和LOCK_SH
(共享锁定) - 如果你的文件系统只是忽略锁定它们就没有意义。
这使我们分别得到独占和共享锁或LOCK_EX
和LOCK_SH
之间的区别。两者背后的逻辑基于写作,但有一点点差异......