【问题标题】:PHP locking not working. Can't figure out whyPHP 锁定不起作用。不知道为什么
【发布时间】:2015-06-25 02:19:50
【问题描述】:

大家好,我正在跟进我的问题 Acquire_lock() not working. Bot still sending requests quickly. PHP + AJAX,我无法得到答案。

我已经简化了所有内容并拥有三个文件

  • abc.txt
  • file1.php
  • file2.php

都在同一个目录下,两个php文件的内容都是一样的:

<?php 
$x = fopen("/var/www/abc.txt", "w"); 
if (flock($x, LOCK_EX|LOCK_NB)) { 
print "No problems, I got the lock, now I'm going to sit on it."; 
while (true) 
    sleep(5); 
} else { 
print "Didn't quite get the lock. Quitting now. Good night."; 
} 
fclose($x); 
?>

然而,当我加载其中任何一个时,我收到第二条打印消息:“没有完全拿到锁。现在退出。晚安。”。

有人对这个问题或前一个问题有任何想法吗?从字面上看,我的智慧就这样结束了。

一如既往的感谢。

【问题讨论】:

  • 我看不出问题出在哪里,除了你的代码在锁定后进入无限循环(我假设你故意让它测试锁?)我在我的本地服务器上测试了这个并且file1.php 不断循环,而 file2.php 立即显示第二条消息。请求的行为到底是什么?
  • @Tarek 我只是想弄清楚锁定是如何工作的。我最终想要的是,如果您运行第一个脚本,然后运行第二个脚本,第二个脚本将等到第一个脚本完成。第一个脚本完成后,第二个脚本将获取锁并完成执行..

标签: php mysql ajax locking bots


【解决方案1】:

这是您的脚本中发生的事情:

1) 你的代码正在进入一个无限循环while(true),它永远不会到达最后的 fclose() 语句。

2) 我在本地服务器上测试了这两个文件:File1.php 一直在循环,而第二个 file2.php 给出的文件被立即锁定消息(这意味着第一个文件正确锁定)。之后我尝试刷新这两个文件,但它们都未能通过锁定测试。

如果您使用的是 PHP> 5.3.2,那么您必须手动解锁文件:

文件的资源句柄关闭时的自动解锁是 删除。现在解锁总是必须手动完成。 Source

如果您使用的是旧版本的 PHP,则脚本将在脚本执行完成后解锁文件,因为您将进入无限循环,脚本永远不会完成,因此文件永远不会解锁。

此外,即使您停止在浏览器窗口中运行脚本,与该脚本相关的进程 php-cgi.exe 仍然在运行,并且必须从任务管理器手动终止(我自己验证过)

解决方案:

1) 要解决此问题并让脚本等待锁定,您首先需要确保脚本实际上通过移除无限循环来正常停止:

这是一个将文件锁定 30 秒的脚本(删除循环):

<?php 
$x = fopen("/var/www/abc.txt", "w"); 
if (flock($x, LOCK_EX|LOCK_NB)) { 
print "No problems, I got the lock, now I'm going to sit on it."; 
sleep(30);
fclose($x); // it is good practice to always close even your PHP <5.3.2
} 
else { 
print "Didn't quite get the lock. Quitting now. Good night."; 
} 

?>

2) 如果你在linux机器上,你可以使用LOCK_NB标志来判断文件是否被锁定。 LOCK_NB的用法应该是这样的:

while ( ! flock($f, LOCK_NB) ) 
{
    sleep(1);
}

这将强制脚本每秒检查一次锁定并等待其他脚本完成。

3) 完成后使用flock($fp, LOCK_UN) 显式移除锁,而不是使用 fclose(); 总之,你的代码应该是这样的:

<?php 
$x = fopen("/var/www/abc.txt", "w");
while(!flock($x,LOCK_NB)
    sleep(1);

if (flock($x, LOCK_EX,true)) { 
print "No problems, I got the lock, now I'm going to sit on it."; 
sleep(30);
fflush($fp);            // flush output before releasing the lock
flock($fp, LOCK_UN);    // release the lock
} else { 
print "Didn't quite get the lock. Quitting now. Good night."; 
} 
fclose($x); 
?>

【讨论】:

  • 我已将#3 复制到 file1.php 和 file2.php 中,运行它们时我得到的只是一个空白屏幕。这是正常的吗?我正在使用 Linux。
  • 不,它应该显示第一条消息。不幸的是,我现在无法访问 linux 机器来测试和调试我的代码。
  • 我在两个文件中都尝试了#1,当我第一次加载 file1.php 时,它显示“没有完全锁定。现在退出。晚安”和同样的如果有帮助的话,对于 file2.php。
  • @Ben 尝试将 true 添加到群中的 willblock 参数,我编辑了我的代码以向您展示如何操作。该建议来自此处的另一个答案。
  • 感谢您的帮助。太奇怪了,因为我到处都在阅读,却没有提到该文件具有适当的权限。也许这是暗示的,idk。
【解决方案2】:

如果您希望 php 脚本不退出,那么您需要一个阻塞锁。

flock 文档说你可以通过指定第三个参数来做到这一点。删除 LOCK_NB 也可能会有所帮助。

<?php 
$x = fopen("/var/www/abc.txt", "w"); 
if (flock($x, LOCK_EX, 1)) { 
    print "No problems, I got the lock, now I'm going to sit on it."; 
    // wait for 5 seconds
    sleep(5);
    // Release the lock now so that next script is executed
    flock($x , LOCK_UN);
} else { 
    print "Didn't quite get the lock. Quitting now. Good night."; 
} 
fclose($x); 
?>

【讨论】:

    猜你喜欢
    • 2013-05-14
    • 2017-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-27
    • 1970-01-01
    相关资源
    最近更新 更多