检查php进程是否已经在运行

6

我正在尝试通过使用一个临时文件demo.lock来检查进程是否已经运行:

demo.php:

<?php
    $active=file_exists('demo.lock');
    if ($active)
    {
        echo 'process already running';
    }
    else
    {
        file_put_contents ('demo.lock', 'demo');
        sleep(10);  //do some job
        unlink ('demo.lock');
        echo 'job done';
    }
?>

然而,它似乎并不起作用:如果我打开demo.php两次,它总是显示“job done”,可能是因为它认为它是同一个进程?有什么办法可以解决吗?我也尝试了使用getmypid(),结果类似。

谢谢


我建议您在这种情况下使用命名互斥量,但我不知道php中是否有这些功能。 - Assaf Lavie
还有,你的操作系统是什么? - zneak
我已经在Windows和Linux机器上都尝试过了,结果相同。 - Borgtex
3个回答

2

对我来说没问题。

确保脚本能够在目录中创建文件。取消注释“unlink”行并运行脚本,检查目录中是否存在锁定文件。如果您没有看到它,则可能是目录权限问题。


对我来说,它不起作用似乎很奇怪。不过,如果权限有误,PHP应该发送警告。 - zneak
你试过注释掉 "unlink" 这一行吗?(对不起,这是 @Borgtex)@zneak 或许他没有看到警告/错误信息... - zaf
权限正确,单次运行中文件被创建然后删除,看起来没有任何问题。问题是当我在浏览器中运行此文件,并在调用它后的5秒内在另一个选项卡中再次调用它时,第二个实例(因为第一个已经在运行且文件已经被创建)会重新执行整个过程,而不是显示警告消息。如果我创建一个名为demo2.php的完全相同的副本,然后一个接一个地运行它们,那么它就会像预期的那样工作;demo等待10秒钟,而demo2立即显示警告。 - Borgtex
它也可以在两个不同的浏览器中运行,也许我应该尝试重定向到另一个页面,并让进程在服务器上运行并忽略用户中止(ignore_user_abort(true))。 - Borgtex
啊,也许是你的浏览器限制了向该网址发送请求的数量。为什么不用计时器计算两个请求所需的时间——如果它们都约为10秒,则我们仍然存在问题;但如果第二个请求大约需要20秒,则你需要调查你的浏览器并增加与网络连接相关的某个浏览器设置(如果有的话)。 - zaf

1

在一个“正常、简单”的环境下,我无法确定你的具体情况出了什么问题,因为它对我来说是有效的,但至少你的代码中存在竞争条件。如果你同时启动两个进程,并且两个进程都发现demo.lock不存在,会怎样呢?

你可以使用fopenx模式来防止这种情况发生。X模式尝试创建文件;如果文件已经存在,则失败并生成一个E_WARNING错误(因此需要使用静默操作符)。由于文件系统操作在驱动器上是原子的,所以保证一次只有一个进程可以持有该文件。

<?php

$file = @fopen("demo.lock", "x");
if($file === false)
{
    echo "Unable to acquire lock; either this process is already running, or permissions are insufficient to create the required file\n";
    exit;
}

fclose($file); // the fopen call created the file already
sleep(10); // do some job
unlink("demo.lock");
echo "Job's done!\n";

?>

我在这里测试过了,看起来它能够正常工作。


谢谢您的建议,我明白使用fopen会增加另一层检查安全性。然而,我仍然有同样的问题;就像第二个实例等待第一个实例结束并删除文件以便重新创建它。 - Borgtex
@Borgtex:那么你的问题超出了我的能力范围。我不知道为什么它会失败。 :/ 好吧,至少我希望我对你有所帮助。 - zneak
不是一个好的解决方案,很多事情可能会出错。 - Flash Thunder

-1
好的,发送一些头信息并刷新似乎对我有用(不确定为什么),所以现在当我加载页面时会显示“开始”,如果我在完成过程之前在浏览器上点击刷新按钮,会出现警告信息。
<?php

$file = @fopen("demo.lock", "x");
if($file === false)
{
    echo "Unable to acquire lock; either this process is already running, or permissions are insufficient to create the required file\n";
    exit;
}

header("HTTP/1.0 200 OK");
ob_start();
echo "Starting";
header('Content-Length: '.ob_get_length(),true);
ob_end_flush();
flush();

fclose($file); // the fopen call created the file already
sleep(10); // do some job
unlink("demo.lock");    
?>

感谢到目前为止所有的答案和建议


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接