gpt4 book ai didi

php - `LOCK_EX` 禁止读,但不能写?

转载 作者:行者123 更新时间:2023-12-02 04:19:09 24 4
gpt4 key购买 nike

为什么我无法读取使用LOCK_EX锁定的文件?我仍然可以写入该文件。

我想知道,如果一个进程锁定一个文件(使用 LOCK_SHLOCK_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";
}
?>

最佳答案

这是一个非常好的问题,但也是一个复杂的问题,因为它取决于很多条件。

我们必须从另一对锁定类型开始 - 建议性锁定和强制锁定:

  • 咨询锁定只是为您提供“状态标志”,您可以通过这些“状态标志”了解资源是否被锁定。
  • 强制锁定强制执行锁定,无论您是否检查这些“状态标志”。

...这应该可以回答您的问题,但我将继续解释您的具体情况。

您似乎遇到的是咨询锁的行为 - 没有什么可以阻止您读取或写入文件,无论是否有锁,或者您是否检查过锁。
但是,您会发现note in the PHP manual for flock() ,说出以下内容:

flock() uses mandatory locking instead of advisory locking on Windows. Mandatory locking is also supported on Linux and System V based operating systems via the usual mechanism supported by the fcntl() system call: that is, if the file in question has the setgid permission bit set and the group execution bit cleared. On Linux, the file system will also need to be mounted with the mand option for this to work.

所以,如果 PHP 在 Windows 上使用强制锁定,并且您已经在 Windows 上测试了这一点,那么手册要么是错误的/过时的/不准确的(我现在懒得检查)或者 您必须阅读同一页面上的红色大警告:

On some operating systems flock() is implemented at the process level. When using a multithreaded server API like ISAPI you may not be able to rely on flock() to protect files against other PHP scripts running in parallel threads of the same server instance!

flock() is not supported on antiquated filesystems like FAT and its derivates and will therefore always return FALSE under this environments (this is especially true for Windows 98 users).

我认为您的 php-cli 可执行文件甚至不可能以某种方式为自身生成线程,因此可以选择您使用的文件系统根本不支持锁定。

我的猜测是,该手册并不完全准确,而且您实际上在 Windows 上获得了咨询锁定,因为您在LOCK_EX (独占锁)和 LOCK_SH(共享锁) - 如果您的文件系统只是忽略锁,那么它们的不同是没有意义的。

这给我们带来了独占共享锁或LOCK_EXLOCK_SH之间的区别。两者背后的逻辑都是基于写作,但有细微的差别......

  • 排他锁(通常)在您想要写入文件时使用,因为一次只有一个进程可以对同一资源持有排他锁。这为您提供了安全性,因为当锁持有者写入该资源时,没有其他进程会读取该资源。
  • 共享锁用于确保在读取资源时不会将其写入资源。由于没有进程写入该资源,因此该资源不会被修改,因此可以安全地同时供多个进程读取。

关于php - `LOCK_EX` 禁止读,但不能写?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31751761/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com