«Отсутствует значение» при вызове «ProcessHandle» `parent (). Get ()` - PullRequest
0 голосов
/ 14 апреля 2019
import java.lang.ProcessBuilder.Redirect;

public class Main {    
  public static void main(String args[]){    
ProcessBuilder pb = new ProcessBuilder(args); 

try{
Process p = pb.start();
   System.out.println("child process is alive: " + p.isAlive());   
   System.out.println("child process pid: " + p.pid());
   System.out.println("parent of child process: " + p.toHandle().parent().get().pid());
   System.out.println("child process is alive: " + p.isAlive());      
   p.waitFor();

} catch (Exception e) {
    System.out.println("some exception with start process.");
    e.printStackTrace();    
}

  }
}

в Ubuntu 18.04, я запускаю программу для запуска внешней программы sleep 10 без проблем:

$ java Main  sleep 10
child process is alive: true
child process pid: 20559
parent of child process: 20539
child process is alive: true
$

Но когда я запускаю программу для запуска внешней программы echo hello

$ java Main  echo hello
child process is alive: false
child process pid: 18534
some exception with start process.
java.util.NoSuchElementException: No value present
    at java.base/java.util.Optional.get(Optional.java:148)
    at Main.main(Main.java:11)

Почему он сообщает об ошибке на get() в строке 11 p.toHandle().parent().get().pid()?

Если я закомментирую строку 11, она будет работать без проблем. Почему это?

Если это потому, что ребенок выходит до вызова p.toHandle().parent().get().pid() в строке 11,

  • почему NoSuchElementException происходит в get() вместо ранее в toHandle() или в parent() в p.toHandle().parent().get().pid() в строке 11?
  • Почему нет такой проблемы при вызове p.pid() в строке 10?

Что я могу сделать, чтобы проблема не возникла? Например, как я могу заставить ребенка работать дольше, чтобы p.toHandle().parent().get().pid() мог работать, даже когда я запускаю недолгую программу в дочернем процессе?

1 Ответ

2 голосов
/ 14 апреля 2019

Почему необязательный аргумент возвращается из parent() пустым при вызове с использованием echo hello?

Поскольку дочерний процесс очень короткий, и когда вы получаете команду, которая запрашивает родительский процесс, дочерний процессболее не существует.Поэтому операционная система больше не может запрашивать об этом процессе.

Почему этого не происходит при вызове getHandle() или pid()?

Обратите внимание, что ни один из них не является Optional.Это означает, что API гарантирует, что значения будут возвращены в них.Фактически реализация такова, что дескриптор создается, включая идентификатор процесса, как только процесс создается операционной системой и возвращается в pb.start().Таким образом, у вас есть дескриптор, и у вас есть идентификатор процесса - но процесс с этим идентификатором не гарантированно останется живым, когда вы его используете.

Документация специально говорит вам не делать предположенийо жизнеспособности или идентичности базового процесса.

В настоящее время вызов parent() осуществляется путем запроса операционной системы с использованием дочернего pid.Таким образом, родительский элемент не является частью записи процесса при создании процесса, и к тому времени, когда вы вызываете его, он может быть недоступен.

Как избежать этой ситуации

При каждом использованииOptional, не используйте get.Особенно не без проверки, присутствует ли он заранее или нет (а использование isPresent ... get считается «антипаттерном»).Когда вы видите, что API дает вам Optional, подумайте, что вы хотите сделать, если этот Optional окажется пустым.Не делайте предположений, которые не обоснованы документацией.

В этом случае вы можете отобразить сообщение по умолчанию, если родитель не найден.Например:

System.out.println("parent of child process: "
    + p.toHandle().parent().map(ProcessHandle::pid)
                           .map(Object::toString)
                           .orElse("not available"));

Или вы можете использовать pid текущего процесса в качестве значения по умолчанию или все, что вы можете придумать.Или вы можете выдвинуть исключение другого рода, если личность родителя абсолютно необходима для вашей работы.Информацию о различных способах элегантной работы с ним см. В документации по Optional.

Нет способа расширить базовый процесс - вы можете использовать сценарий оболочки, который спит после выполнения переданной вами команды, ноЯ считаю, что это решение в лучшем случае неуклюже.

...