Почему выполнение интерактивного процесса с перенаправленными потоками ввода / вывода приводит к остановке приложения? - PullRequest
1 голос
/ 14 ноября 2010

У меня есть консольная Java-программа, которая выполняет sh -i в отдельном процессе и копирует данные между потоком ввода-вывода процессов и соответствующими системными потоками:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

class StreamCopier implements Runnable {
    private InputStream in;
    private OutputStream out;

    public StreamCopier(InputStream in, OutputStream out) {
        this.in = in;
        this.out = out;
    }

    public void run() {
        try {
            int n = 0;
            byte[] buffer = new byte[4096];
            while (-1 != (n = in.read(buffer))) {
                out.write(buffer, 0, n);
                out.flush();
            }
        } catch (IOException e) {
            System.out.println(e);
        }
    }
}

public class Test {
    public static void main(String[] args)
            throws IOException, InterruptedException {
        Process process = Runtime.getRuntime().exec("sh -i");
        new Thread(new StreamCopier(
                process.getInputStream(), System.out)).start();
        new Thread(new StreamCopier(
                process.getErrorStream(), System.err)).start();
        new Thread(new StreamCopier(
                System.in, process.getOutputStream())).start();
        process.waitFor();
    }
}

Запуск его под Linux приводит к следующему:

$ 
[1]+  Stopped                 java -cp . Test

Может кто-нибудь уточнить, почему приложение остановлено и как его избежать?

Это связано с моим вопросом о копировании потоков , но я думаю, что этот конкретный вопрос заслуживает отдельного внимания.

Ответы [ 2 ]

1 голос
/ 15 ноября 2010

Вы можете отключить управление заданиями, вызвав оболочку, как sh -i +m, что остановит ее захват tty.Это означает, что команды fg и bg не будут работать, и Ctrl + Z приостановит ваше Java-приложение, оболочку и все программы, запущенные из него.

Если вы все еще хотите контролировать работу, вам следуетиспользуйте псевдотерминал для связи с оболочкой, что создает новый tty для использования оболочкой, но я не думаю, что Java поддерживает это.

1 голос
/ 14 ноября 2010

Вас останавливает SIGTTIN или SIGTTOU. Эти сигналы отправляются в фоновый процесс, когда они пытаются выполнить ввод-вывод в TTY. В этом случае «фон» означает «не управляющая группа процессов терминала». Я подозреваю, что подоболочка, которую вы отбрасываете, создает новый pgrp и захватывает ваш tty. Затем родительская программа (java) выполняет IO (в вашем случае, вероятно, читает из TTY) и получает SIGTTIN.

Простой способ подтвердить эту теорию - заменить sh чем-то более простым (не оболочкой), которое не будет пытаться захватить tty.

...