4

これは完全に再現可能なコードです。

<?php
class console{
    public static function log($msg, $arr=array()){
        $str = vsprintf($msg, $arr);
        fprintf(STDERR, "$str\n");
    }
}
function cleanup(){
    echo "cleaning up\n";
}
function signal_handler($signo){
    console::log("Caught a signal %d", array($signo));
    switch ($signo) {
        case SIGTERM:
            // handle shutdown tasks
             cleanup();
            break;
        case SIGHUP:
            // handle restart tasks
            cleanup();
            break;
        default:
            fprintf(STDERR, "Unknown signal ". $signo);
    }
}

if(version_compare(PHP_VERSION, "5.3.0", '<')){
    // tick use required as of PHP 4.3.0
    declare(ticks = 1);
}

pcntl_signal(SIGTERM, "signal_handler");
pcntl_signal(SIGHUP, "signal_handler");

if(version_compare(PHP_VERSION, "5.3.0", '>=')){
    pcntl_signal_dispatch();
    console::log("Signal dispatched");
}

echo "Running an infinite loop\n";
while(true){
    sleep(1);
    echo date(DATE_ATOM). "\n";
}

これを実行すると、毎秒日付の値が表示されます。Ctrl+Ccleanup関数を押しても呼び出されません。実際signal_handlerには呼び出されません。

出力例を次に示します。

$ php testsignal.php 
Signal dispatched
Running an infinite loop
2012-10-04T13:54:22+06:00
2012-10-04T13:54:23+06:00
2012-10-04T13:54:24+06:00
2012-10-04T13:54:25+06:00
2012-10-04T13:54:26+06:00
2012-10-04T13:54:27+06:00
^C
4

3 に答える 3

11

ハンドラーをインストールしていないCTRL+Cfires :SIGINT

<?php
...
function signal_handler($signo){
...
    case SIGINT:
        // handle restart tasks
        cleanup();
        break;
...
}
...
pcntl_signal(SIGINT, "signal_handler");
...

今では動作します:

$ php testsignal.php
Signal dispatched
Running an infinite loop
2012-10-08T09:57:51+02:00
2012-10-08T09:57:52+02:00
^CCaught a signal 2
cleaning up
2012-10-08T09:57:52+02:00
2012-10-08T09:57:53+02:00
^\Quit
于 2012-10-08T08:02:14.620 に答える
0

宣言ティックのコンパイル時の使用に対する Ruben de Vries の修正に続いて、元のコードには 2 つの問題があります (INT シグナルの欠落以外)。

ルーベンが言うように:

if(false) declare(ticks=1);

これは、ティックが処理されることを宣言します。それを試してみてください!ドキュメントには、変数などを使用できない方法が記載されています。これはコンパイル時のハックです。

さらに、 の使用はtick の宣言の単純な置き換えでpcntl_signal_dispatch()はありません。これはコードの実行中に呼び出す必要があります。これは tick が自動的に行うようにです。したがって、そのようにスクリプトの先頭で一度呼び出すと、その時点で保留中のシグナルのみが処理されます。

pcntl_signal_dispatch() をティックを使用して駆動するように動作させるには、割り込みを有効にする場所/タイミングに応じて、コード全体に振りかける必要があります。

少なくとも:

while(true){
    sleep(1);
    echo date(DATE_ATOM). "\n";
    pcntl_signal_dispatch();
}

したがって、元のコードは、実際にはすべてのバージョンの PHP でティックを使用しており、さらに、バージョンが 5.3 よりも大きい場合、最初のブート プロセス中に受信したシグナルを 1 つだけチェックしています。OPが意図したものではありません。

個人的には、ティックを使用して PCNTL シグナルを駆動するのは非常に厄介な苦痛です。私の場合の「ループ」はサードパーティのコードにあるため、ディスパッチ メソッドを追加することはできません。また、すべてのファイルに追加しない限り、トップ レベルでティックを宣言しても運用環境では機能しません (オートロード、スコープ、または PHP7バージョン固有の問題だと思います)。

于 2017-08-13T08:44:36.907 に答える