Главная » Java » Создание процессов

0

Как упоминалось выше, в программах Java могут одновременно выполняться несколько потоков. Большинство систем, на которых функционирует среда Java, также поддерживают запуск нескольких программ. Приложения Java могут вызывать новые программы, обращаясь к одной из двух форм метода System.exec. Каждый успешный вызов exec создает новый объект Process, который представляет собой работающую программу. Вы можете запросить информацию о состоянии процесса и вызвать методы, управляющие его ходом. Существуют две основные формы метода exec:

public Process exec(String[] cmdarray) throws IOException

Выполняет в текущей системе команду, заданную в объекте cmdarray, и возвращает объект Process (описанный ниже), который представляет запущенный процесс. В cmdarray[0] задается имя команды, а во всех последующих строках массива — аргументы.

public Process exec(String command) throws IOException

Эквивалентен первой форме exec, в которой элементы массива собраны в одну строку и разделены символами-разделителями. Приведем пример использования этой формы exec:

String cmd = “/bin/ls” + opts + “ ” + dir;

Process child = Runtime.getRuntime().exec(cmd);

Порожденный процесс носит название процесса-потомка  (child process ). По аналогии, создающий процесс называется родителем. Метод exec возвращает объект Process для каждого запущенного процесса-потомка.  Этот объект обладает двумя важными аспектами по отношению к процессу-потомку:  во-первых, он содержит методы для обращения ко входному и выходному потоку процесса-потомка,  а также к его потоку ошибок:

public abstract OutputStream getOutputStream()

Возвращает поток OutputStream, соединенный со входным потоком процесса-потомка. Данные, записанные в этот поток, считываются процессом-потомком в качестве ввода. Поток является буферизованным.

public abstract InputStream getInputStream()

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

public abstract InputStream getErrorStream()

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

Ниже в качестве примера приводится программа, которая соединяет стандартные потоки Java с потоками нового процесса, чтобы весь ввод пользователя поступал в указанную программу, а весь ее вывод был виден пользователю:

public static Process UserProg(String cmd)

throws IOException

{

Process proc = Runtime.getRuntime().exec(cmd); plugTogether(System.in,  proc.getOutputStream()); plugTogether(System.out, proc.getInputStream()); plugTogether(System.err, proc.getErrorStream()); return proc;

}

Предполагается, что метод plugTogether соединяет два потока, читая данные из одного из них и записывая их в другой.

Упражнение 14.1

Напишите метод plugTogether. Подсказка: воспользуйтесь многопоточной моделью.

Второй аспект взаимоотношений  между процессом-родителем и процессом-потомком заключается в том, что объект Process содержит методы для управления процессом и определения его статуса:

public abstract int waitFor() throws InterruptedException

Сколь угодно долго ожидает завершения процесса-потомка  и возвращает значение, переданное им методу System.exit или его аналогу (ноль означает успешное завершение, все остальное — неудачу). Если процесс уже завершился, то просто возвращается значение.

public abstract int exitValue()

Возвращает завершающий код данного процесса. Если процесс еще активен, то exitValue

возбуждает исключение IllegalStateException. public abstract void destroy()

Уничтожает процесс. Ничего не делает, если процесс уже завершился. Если объект

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

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

// java.io.*  и java.util.* импортированы

public String[] ls(String dir, String opts)

throws LSFailedException

{

try {

// запустить процесс

String[] cmdArray = { "/bin/ls", opts, dir };

Process child = Runtime.getRuntime().exec(cmdArray); DataInputStream

in = new DataInputStream(child.getInputStream());

// прочитать выходные данные Vector lines = new Vector(); String line;

while ((line = in.readLine()) != null)

lines.addElement(line);

if (child.waitFor() != 0)  // если выполнение ls

// было неудачным

throw new LSFailedException(child.exitValue()); String[] retval = new String{lines.size()]; lines.copyInto(retval);

return retval;

} catch (LSFailedException e) {

throw e;

} catch (Exception e) {

throw new LSFailedException(e.toString());

}

}

Класс Process является абстрактным. Каждая реализация Java должна содержать один или несколько классов, расширяющих Process, которые могут взаимодействовать  с

процессами на уровне операционной системы. Такие классы могут обладать расширенным

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

Две другие формы exec позволяют задать набор переменных среды (environment variables

) — системно-зависимых переменных, доступных для нового процесса. Переменные среды передаются методу exec в виде строкового массива, каждый элемент которого задает имя и значение переменной среды в форме имя = значение. Имя не может содержать пробелов, хотя значение может быть произвольным. Переменные среды передаются вторым параметром:

public Process exec(String command, String[] env)

throws IOException

public Process exec(String[] command, String[] env)

throws IOException

Способ интерпретации переменных среды процессом-потомком является системно- зависимым. Механизм переменных среды поддерживается потому, что он существует на самых разных платформах. Для передачи информации между Java-программами  следует пользоваться свойствами, а не переменными среды.

Упражнение 14.2

Напишите программу, которая выполняет exec для аргументов, переданных в командной строке, и выводит результаты работы, причем каждой строке предшествует ее номер.

Упражнение 14.3

Напишите программу, которая выполняет exec для аргументов, переданных в командной строке, и выводит результаты, прекращая работу процесса, когда на выходе появляется заранее определенная строка.

Источник: Арнольд К., Гослинг Д. – Язык программирования Java (1997)

По теме:

  • Комментарии