为什么我无法读取用 锁定的文件 LOCK_EX?我仍然可以写信给它。
我想知道,如果一个进程锁定一个文件(使用LOCK_SH或LOCK_EX)而另一个进程尝试读取该文件或写入该文件,但完全忽略该锁定,会发生什么。所以我制作了一个具有 3 个功能的小脚本:
我通过并排放置两个控制台并执行以下操作来测试它:
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
Run Code Online (Sandbox Code Playgroud)
LOCK_SH似乎根本没有影响,因为第一个进程和第二个进程都可以读写文件。如果文件被LOCK_EX第一个进程锁定,两个进程仍然可以写入它,但只有第一个进程可以读取。这背后有什么道理吗?
这是我的小测试程序(在Windows 7 Home Premium 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";
}
?>
Run Code Online (Sandbox Code Playgroud)
这是一个很好的问题,但也是一个复杂的问题,因为它取决于很多条件。
我们必须从另一对锁定类型开始——建议和强制:
...这应该可以回答你的问题,但我会继续解释你的特殊情况。
您似乎正在经历的是咨询锁的行为 - 没有什么可以阻止您读取或写入文件,无论是否有锁,或者您是否检查过。
但是,您会在 PHP 手册中找到 flock()的注释,内容如下:
flock() 在 Windows 上使用强制锁定而不是建议锁定。通过 fcntl() 系统调用支持的常用机制,基于 Linux 和 System V 的操作系统也支持强制锁定:也就是说,如果有问题的文件设置了 setgid 权限位并清除了组执行位。在 Linux 上,还需要使用 mand 选项挂载文件系统才能使其工作。
所以,如果 PHP 在 Windows 上使用强制锁定并且你已经在 Windows 上测试过,要么手册是错误的/过时的/不准确的(我现在懒得检查)或者你必须阅读这个红色的大警告同一页面:
在某些操作系统上, flock() 是在进程级别实现的。当使用像 ISAPI 这样的多线程服务器 API 时,您可能无法依靠 flock() 来保护文件免受在同一服务器实例的并行线程中运行的其他 PHP 脚本的侵害!
flock() 在过时的文件系统(如 FAT 及其派生类)上不受支持,因此在这种环境下将始终返回 FALSE(对于 Windows 98 用户尤其如此)。
我不相信您的 php-cli 可执行文件以某种方式为自己生成线程,因此您可以选择使用根本不支持锁定的文件系统。
我的猜测是该手册并不完全准确,实际上您确实在Windows 上获得了咨询锁,因为您在LOCK_EX(排他锁)和LOCK_SH(共享锁)之间也遇到了不同的行为- 它们没有意义如果您的文件系统只是忽略锁,则不同。
这给我们带来了排他锁和共享锁之间的区别,或者分别是LOCK_EX和LOCK_SH。两者背后的逻辑都基于write,但略有不同......
| 归档时间: |
|
| 查看次数: |
1071 次 |
| 最近记录: |