PHP - proc_get_status 'выполняется', возвращая false, когда исполняемый файл javaw все еще работает

Я выполняю javaw с java-файлом с бесконечным циклом, используя это:

$descriptorspec = array(
                                0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
                                1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
                                2 => array("pipe", "w") // stderr is a file to write to
                        );

 // e.x. $javaCmd = "java -cp "../Fully Diversified Sequences of Sets" SuperEasyProblemSolution2 > /dev/null 2>&1 < h.in"
$proc = proc_open($javaCmd, $descriptorspec, $pipes);//, $cwd, $env);
 stream_set_blocking($pipes[0], 0) ;

 $status = proc_get_status($proc);  
 var_dump($status);
  $timeOut = 5;
  $currentSecond = 0;

  while( $currentSecond < $timeOut ) {
        echo '<br/>';
        sleep(1);
        $currentSecond = $currentSecond +1;
        if( ! $status["running"] )
        {
            echo 'process exited before timing out'; // Process must have exited, success!
            return;
        }
        $status = proc_get_status($proc);
        var_dump($status);
  } // end while
  if($currentSecond  == $timeOut)
  {
      // kill KILL KILL!
      exec("taskkill /PID ".$status['pid']);
  }

По первому звонку proc_get_status, running атрибут возвращает истину. На втором звонке (через секунду) proc_get_status, running возвращает ложь Приложение javaw.exe все еще работает, однако (я звоню proc_get_status в то время как цикл, который в конечном итоге будет тайм-аут.)

Моя цель - убить программу по истечении времени ожидания. Смотрите аналогичный вопрос здесь. Я работаю на Win7 64 бит, PHP 5.3

Вар дамп на $status: (Примечание; я пытался подать заявку stream_set_blocking($pipes[0], 0) ; та же проблема)

Перед входом в цикл ожидания:

    array(8) { 
["command"]=> string(157) "java -cp "../Fully Diversified Sequences of Sets" SuperEasyProblemSolution2 /dev/null 2>&1 < h.in" 
["pid"]=> int(3264) 
["running"]=> bool(true) 
["signaled"]=> bool(false) 
["stopped"]=> bool(false) 
["exitcode"]=> int(-1) 
["termsig"]=> int(0) 
["stopsig"]=> int(0) 
} 

После первой итерации / сна (1):

    array(8) { 
["command"]=> string(157) "java -cp "../Fully Diversified Sequences of Sets" SuperEasyProblemSolution2 /dev/null 2>&1 < h.in" 
["pid"]=> int(3264) 
["running"]=> bool(false) 
["signaled"]=> bool(false) 
["stopped"]=> bool(false) 
["exitcode"]=> int(1) 
["termsig"]=> int(0) 
["stopsig"]=> int(0) 
} 
    process exited before timing out

После тестирования выясняется, что $status['pid'] отличается от pid для javaw.exe в Windows' Resource Monitor.

3 ответа

Решение

Хотя мы не могли точно определить проблему с proc_get_status, возвращающим неверный логический тип, мы смогли найти хороший обходной путь (для Unix), используя

if (file_exists("/proc/".$status["pid"])) { // process still running }

чтобы проверить, был ли процесс все еще запущен или нет.

Вот полный фрагмент кода:

$proc = proc_open($javaCmd, array(array("pipe", "r"), array("pipe", "w"), array("pipe", "w")), $pipes);

$status = proc_get_status($proc);

if($status["pid"] === false)
{
    // Process did not execute correctly
}
else
{
        $timeOut = 0;
        $forceKill = true;

        while($timeOut < $timeLimit)
        {
            $timeOut++;
            sleep(1);
            echo 'Timeout is at '.$timeOut.' and timelimit: '.$timeLimit.'<br/>';

            if (file_exists("/proc/".$status["pid"])) {
            // process still running
            }
            else
            {
                echo 'Finished running after '.$timeOut.' seconds<br/>';
                $forceKill = false;
                break;
            }

        }
        if($forceKill == true)
        {
            echo ' Manual killing pid '.$status['pid'];
            exec("sudo kill ".$status['pid']);
            $runTime = $timeLimit;
        }


}

Если приложение Java работает как демон, то оно будет иметь другой PID.

Приложение Java пытается вывести что-нибудь? Если так - тогда вы не читаете канал, поэтому скрипт в конечном итоге заполнит буфер и зависнет (что может привести к остановке работы Java)

Если вас не волнует вывод, отправьте его на /dev/null чтобы избавиться от этого:

/cmd/to/run > /dev/null 2>&1

Если вы решите читать данные из канала, функция чтения будет блокироваться, если данных нет, чтобы обойти то, что вы, возможно, захотите использовать:

stream_set_blocking($pipes[0], 0)

Это отключит режим блокировки (функция чтения вернется FALSE немедленно, если нет данных, ожидающих).

Так как вы упомянули, что вы делаете это на окнах, я понял, что происходит-

javaw (с буквой W) запускает его как приложение для Windows и сразу же возвращает (поэтому работает =false)

вам нужно использовать Java (без W), чтобы запустить его в консоли.

java = console application
javaw = windows application with no console
Другие вопросы по тегам