【问题标题】:php signal not handled right awayphp 信号未立即处理
【发布时间】:2015-05-05 15:29:33
【问题描述】:

我有一个用 PHP 编写的软件,可以运行很长时间,它是通过命令行启动的(不是 Web 应用程序)。我想确保在软件退出时调用一个函数,包括通过 ctrl+c 杀死时。当被信号杀死时,关闭函数(通过 register_shutdown_fucntion() 注册的析构函数和函数)不会被调用。

经过阅读,我意识到我必须在每个相关信号上添加一个处理程序才能调用“exit;”。这样做解决了我的问题并且有效。

我的问题是,在某些情况下,信号没有立即处理。它可能需要几秒钟,几分钟,在某些情况下,根本不处理。就像从未到达处理程序代码一样。我真的不知道从哪里开始调试。我尝试过其他信号(sigkill、sighup 等),行为相同。

我的代码用这些括号

declare(ticks=1)
{...}

我找不到立即治疗的时间和不立即治疗的时间之间的任何相关性。

任何帮助将不胜感激。

【问题讨论】:

    标签: php signals pcntl


    【解决方案1】:

    信号应该这样处理: 首先,你必须像这样制作一个信号处理程序:

    function signalHandler($signo = null) {
        $pid = posix_getpid();
        switch ($signo) {
            //case SIGKILL: // you can't override SIGKILL so it is useless
            case SIGTERM:
            case SIGINT:
                // unexpected shut down
                exit(3);
                break;
            case SIGCHLD:
            case SIGHUP:
                // just ignore it
                break;
            case 10:
                // user signal 1 received. Process exited normally
                exit(0);
                break;
            case 12:
                // user signal 2 received. Precess exited with a catched error
                exit(3);
                break;
            default:
                // ignore other signals
        }
    }
    

    然后,在你的主进程中,你必须告诉 PCNTL 你正在使用这个处理程序:

        pcntl_signal(SIGTERM, "signalHandler");
        pcntl_signal(SIGINT, "signalHandler");
    //  pcntl_signal(SIGKILL, "signalHandler"); // you can't override SIGKILL so it is useless
        pcntl_signal(SIGCHLD, "signalHandler");
        pcntl_signal(SIGHUP, "signalHandler");
        pcntl_signal(10, "signalHandler");
        pcntl_signal(12, "signalHandler");
    

    我正在使用它,似乎可以为 200 个进程工作,同时运行 8 个进程,每个进程 10 秒。

    这里,当一个进程退出时,他使用posix_kill($pid, 10)发送一个信号10或12(表示成功或错误)

    【讨论】:

    • 让我指出 switch 语句的“SIGKILL”部分是完全没有必要的,因为“SIGKILL”是一个无法捕获的信号,因此执行将永远不会到达该部分。这是unix中的一种安全措施。即使您的代码无法处理 SIGTERM/SIGHUP/等。出于某种原因,SIGKILL 将始终作为关闭进程的最后手段。
    • @GergelyLukacsy 确实,SIGKILL 无法被捕获,能够杀死一个进程,无论它做什么,它都是女仆。所以对于恶意程序来说,如果它能够捕捉到 SIGKILL 信号(并因此忽略它),那将是一件坏事。所以 SIGTERM 和 SIGINT 的意思是你问程序“你能关闭吗?”,使其能够安全地关闭连接等......,而 SIGKILL 是“我移除了你的营养电缆,你将关闭,无论你在做什么” .我把它从交换机上取下来了,谢谢
    【解决方案2】:

    我认为这里的问题是,也许您调用了一个包含循环的函数,并且循环的每次迭代都需要大量时间(例如,从数据库中获取数据)。在这种情况下,当你的程序接收到一个停止信号时,它会将该信号添加到堆栈中,等待,直到从数据库中获取数据,然后调用信号处理函数。

    我也在寻找一种立即调用信号处理函数的方法。也许 PHP 只是没有这个选项。

    更新:

    我想我找到了解决方案。尝试将false 作为第三个参数传递给函数pcntl_signal(),如下所示:

    pcntl_signal(SIGINT, function () {
        echo 'Do something here.';
    }, false);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多