8

私が持っているコードの基本的な説明をすることから始めましょう。メインの親プロセスから始めます (注: 簡単にするためにすべての機能を示しているわけではありません。拡張が必要な​​場合はいつでもお知らせください)。

declare(ticks=1);
pcntl_signal(SIGHUP, array('forker', 'restartSignalHandler'));
if(forker_is_not_running()){
    new Forker();
}
class Forker {
    private $active_forks = array();
    private $parent_pid = null;

    public function __construct(){
        $this->parent_pid = getmypid();
        $this->create_fork();
        $this->wait_for_active();
    }

    public function wait_for_active(){
        while(!empty($this->active_forks)){
            foreach($this->active_forks as $k=>$fork){
                if($this->fork_no_longer_running($fork)){
                    unset($this->active_forks[$k]);
                }
            }
        }
    }

    // Pseudo code
    public function fork_no_longer_running($pid){
        // return true if 'ps -elf | grep $pid' doesn't returns only the grep command
        // else return false (aka the fork is still running)
    }

    public function create_fork(){
        $pid = pcntl_fork();
        if($pid == -1){
            posix_kill($this->parent_pid, SIGTERM);
        } else if($pid){
            // add the pid to the current fork
            $this->active_forks[] = $pid;
        } else {
            // Run our process
            pcntl_exec('/usr/bin/php', array('/domain/dev/www/index.php','holder','process'));
            exit(0);
        }
    }

    public function restartSignalHandler(){
        $forks = $this->active_forks;
        foreach($forks as $pid){
            $this->create_fork();
            posix_kill($pid, SIGINT);
        }
    }
}

class holder {
    public function process(){
        $x = new Processor();
    }
}

class Processor {
    public function __construct(){
        pcntl_signal(SIGINT, array($this, "shutdownSignalHandler"));
    }
    public function shutdownSignalHandler(){
        echo "Shutting down";
        exit;
    }
}

何が起こっているかは次のとおりです。

  1. スクリプトを開始し、プロセスを適切に取得します (例: Parentpid:2、childpid:3)。
  2. 次に、親に SIGHUP シグナルを送信すると、適切に強制終了され、新しい子プロセスが開始されます (たとえば、Parentpid: 2、childpid:4)。
  3. 次に、親に 2 番目の SIGHUP シグナルを送信すると、新しい子プロセスを適切に試行して追加しますが、2 番目の childpid を強制終了することを拒否します。(例: Parentpid:2、undyingchildpid:4、newchildpid:5)

詳細が必要かどうか、または意味がないかどうかを教えてください。初めて子供たちを適切に殺す理由がわかりませんが、2回目はそうではありません。

さらに厄介な部分は、再起動ハンドラーを変更して、SIGINT で子を殺そうとし続けるように変更すると、毎回失敗しますが、SIGKILL コマンドを送信すると、子プロセスが強制終了されることです。

if($time_passed > 60){
    posix_kill($pid, SIGKILL);
}

適切に処理するには、子供が SIGINT によって殺される必要があります。私はそれをSIGKILLしたくありません。2 回目の SIGINT が機能しない理由はありますが、SIGKILL は機能しますか?

4

1 に答える 1

1

まず、フォークする必要はありません。コードは子内で実行を行います。基本的には、分岐せずに実行を実行するだけで、OS はコマンドを子として生成します。fork を使用する場合はinclude、実行するのではなく、子のファイルだけを使用します。

public function create_fork(){
    //no need to actually fork!
    pcntl_exec('/usr/bin/php', array('/domain/dev/www/index.php','holder','process'));
}

//if you want to fork, better do it like this : 


public function create_fork(){
    $pid = pcntl_fork();
    if($pid == -1){
        posix_kill($this->parent_pid, SIGTERM);
    } else if($pid){
        // add the pid to the current fork
        $this->active_forks[] = $pid;
    } else {
       // Run our process
       include '/domain/dev/www/index.php';
       SomeClass::someMethod();
       exit(0);
    }
}

waitpidまた、フォークを使用する場合は、子供のために必要です。したがって、コードに次のようなものを挿入する必要があります。

//somewhere in a loop : 
$pidOfExittedChild = pcntl_waitpid (-1, $status, WNOHANG);
if ($pidOfExittedChild) {
    //a child has exitted, check its $status and do something
}

詳しくはhttp://php.net/manual/en/function.pcntl-waitpid.phpをご覧ください。

于 2012-04-02T10:44:37.413 に答える