Есть ли риск состояния гонки при запуске ps?

Я начинаю длительный процесс (в Java, по независящим от него), и хотел бы затем захватить его PID через ps . Я по существу делаю это:

 Process longRunningProcess = new ProcessBuilder(...).start(); Process psProcess = new ProcessBuilder("ps").start(); psProcess.waitFor(); // extract the PID from the output of psProcess 

Или эффективно эквивалентно в Bash:

 $ long_running_process > /dev/null & ps 

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

В этой статье предупреждается, что при запуске ps (например, ps | grep ) могут появляться условия гонки, но ничего не говорится о процессах, запущенных до ps .

3 Solutions collect form web for “Есть ли риск состояния гонки при запуске ps?”

Если операции сопоставимы с OpenJDK v6-b14 , PID будет доступен для ps при сканировании виртуальной файловой системы /proc . Вы не можете быть уверены, что процесс действительно начался (т. Е. Сделал что-либо); все, что вы знаете, это то, что PID зарезервирован и запланирован (подумайте об этом, процесс мог бы погибнуть и находиться в состоянии зомби).

Тем не менее, поскольку ps блокирует вас в Unix-системах, вы можете использовать Reflection для поиска в объекте, возвращаемом ProcessBuilder, при условии, что он приведет вас к UnixProcess:

 final class [More ...] UNIXProcess extends Process { private FileDescriptor stdin_fd; private FileDescriptor stdout_fd; private FileDescriptor stderr_fd; private int pid; <---------------------------------------------- private int exitcode; 

Конечно, это взломать, но не слишком отличается от нереста ps – и, конечно же, быстрее. И на самом деле все это не так рискованно – я не вижу, что поле pid под названием pid меняется очень скоро.

Я не знаком с Java, но к моменту ProcessBuilder.start он должен что-то начать. Он может настроить обратный вызов внутри существующего потока, который будет выполнен позже, чтобы создать дочерний процесс, или он может запустить другой поток в том же процессе, который в конечном итоге создает дочерний процесс, или он может вызвать fork для создания дочернего процесса , Я сомневаюсь, что это какой-то из первых двух, поскольку было бы труднее получить право; любая ссылка на подпроцесс, включая механизмы для связи с ним или для получения его статуса, должна будет ждать, пока процесс не будет создан.

Таким образом, к моменту ProcessBuilder.start вы можете быть уверены, что процесс был создан. Однако это не означает, что нет условий гонки. Если процесс завершится или произойдет сбой вскоре после его запуска, он может быть уже мертв к тому моменту, когда вы посмотрите на него. Идентификатор процесса будет существовать до тех пор, пока его родительский вызов не вызовет одно из семейств системных вызовов wait ; если процесс умер, PID остается действительным, пока процесс является зомби , т. е. пока родитель не вызвал wait .

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

Я столкнулся с этой проблемой в прошлом. Я решил это, сделав:

 exec java WhateverTheClassNameIs -p $$ 

где «-p» – это флаг, указывающий «мой PID – это значение этого флага». Вы должны записать эту часть в свой метод Java main() .

Это должна быть последняя строка сценария оболочки, так как примитив exec загружает java поверх самой оболочки. Статус выхода вашей программы будет статусом выхода WhateverTheClassNameIs , а не статусом выхода оболочки, поскольку он больше не существует. Это может привести к несколько искаженному коду, но я не смог найти лучший способ получить PID в программе Java.

  • Печать как Firefox
  • сортировка вывода ps по времени процессора на linux
  • «Ps» вывод и комментарии
  • Лучше / предпочтительнее убивать все дочерние процессы с помощью PPID или PGID?
  • Значительная часть используемой памяти не учитывается пользовательскими процессами
  • Выясните PID точного приложения node.js
  • ps | grep показывает плохой результат в подоболочке с заданиями, работающими в фоновом режиме
  • UNIX-, BSD-, GNU-опции в команде ps для Linux. Откуда они?
  • init: это пользовательский поток или поток ядра?
  • разница между bash, -bash и / bin / bash в выпуске ps
  • Как я могу получить полный список процессов в Solaris без усеченных линий?
  • Linux и Unix - лучшая ОС в мире.