【发布时间】:2015-10-23 11:06:29
【问题描述】:
为什么我无法读取被LOCK_EX锁定的文件?我仍然可以写入。
我想知道,如果一个进程锁定了一个文件(使用LOCK_SH 或LOCK_EX),而另一个进程尝试读取或写入该文件,但完全忽略了锁定,会发生什么情况。所以我做了一个小脚本,它有 3 个功能:
- 锁定:打开目标文件,写入,锁定文件(使用指定的锁),再次写入,休眠 10 秒,解锁并关闭。
- 读取:打开目标文件,从中读取并关闭它。
- 写入:打开目标文件,写入并关闭它。
我通过并排放置两个控制台并执行以下操作对其进行了测试:
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 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";
}
?>
【问题讨论】: