Многопроцессорная связь через построитель процессов, зависание в readline() для BufferedReader()

Я пытаюсь разрешить связь между одной программой (программой запуска, если хотите) и программами, которые она запускает через построитель процессов. У меня вывод работает нормально, но ввод, кажется, останавливается, когда он достигает метода readline() в helloworld (созданный процесс).

Ниже приведен файл helloworld.java:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;


public class helloworld {
public static void main (String[] args) {
System.out.println ("println(\"Hello World!\")");
System.out.println ("getInput()");
Scanner in = new Scanner(System.in);
BufferedReader br = new BufferedReader(
        new InputStreamReader(System.in));
String input = "";
try {
    // wait until we have data to complete a readLine()
    while (!br.ready()) {
      Thread.sleep(200);
    }
    System.out.println("println(\"Attempting to resolve input\")");
    input = br.readLine();  

^Здесь программа зависает^

    if(input != null){
        System.out.println("println(\"This should appear\")");
    }
    System.out.println("println(\"input recieved " + input + "\")");
} catch (InterruptedException | IOException e) {
    System.out.println("ConsoleInputReadTask() cancelled");
  }

System.out.println("println(\"You said: " + input + "\")");
//System.out.println("println(\"You said: " + in. + "!\")");

in.close();
System.exit(0);
}
}

Здесь получаются выходные данные (println) другого процесса:

public void run() {
    try {
        //cfile = files[indexval].getAbsolutePath();
        String[] commands = 
            {
                "java", //Calling a java program
                "-cp" , //Denoting class path
                cfile.substring(0,cfile.lastIndexOf(File.separator) ), //File path
                program}; //Class name

        ProcessBuilder probuilder = new ProcessBuilder( commands );

        //start the process
        Process process = probuilder.start();

        //Read out dir output
        //probuilder.inheritIO(); //Can inherit all IO calls
        InputStream is = process.getInputStream();
        OutputStream os = process.getOutputStream();
        InputStreamReader isr = new InputStreamReader(is);
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
        BufferedReader br = new BufferedReader(isr);
        String line;
        /*System.out.printf("Output of running %s is:\n",
                Arrays.toString(commands));*/
        while ((line = br.readLine()) != null) {
            myController.runCommand(line, "Please enter something!", bw);
            //System.out.println(line);
        }
        br.close();
        os.close();
        } catch (IOException e){
            e.printStackTrace();
        }
    System.out.println("programclosed");
}

А вот функция, которую он вызывает:

public synchronized void runCommand(String line, Object... arguments) throws     IOException {
    String[] tokens;
    if(line.contains("(")){
        tokens = line.split("\\(",2);

    switch(tokens[0]){
    case "println": //Println - format println(String strng)
        tokens[1] = tokens[1].substring(1, tokens[1].length() - 2);
        System.out.println(tokens[1]);
        break;
    case "getInput": //Get input - format getInput(String command, String message, BufferedWriter br)
        Scanner reader = new Scanner(System.in);
        System.out.println(arguments.length);
        System.out.println(((String)arguments[0]));
        BufferedWriter in = ((BufferedWriter)arguments[1]);
        in.write(reader.nextLine());
        System.out.println("sending input");
        in.flush();
        reader.close();
        break;
    default:
        System.out.println("Invalid command recieved!");
    }
    } else
        System.out.println("Invalid command recieved!");


}

Результат, который я получаю:

Привет, мир!

2 Пожалуйста, введите что-нибудь!

Это тестовый ввод

отправка ввода

Попытка разрешить ввод

Как видите, я успешно выхожу из цикла while(!br.ready()) и останавливаюсь на br.readLine();

Я знаю, что inheritIO() существует, но в этом случае я использую BufferedOuput для отправки команд, которые затем анализируются и отправляются в оператор switch, который, в свою очередь, вызывает соответствующую функцию. Это связано с тем, что несколько процессов могут быть запущены из диспетчера процессов, представьте себе удовольствие, когда поступает несколько вызовов System.in, и ничто не может определить, для какого процесса он предназначен! Кроме того, это позволяет мне вызывать функции любого типа, даже те, которые не связаны с println или вводом.


person Jeff B    schedule 12.04.2015    source источник
comment
Избавьтесь от бессмысленного цикла вращения, вызывающего ready().. Следующий вызов .readLine() уже будет заблокирован и точно на нужный период времени, в отличие от этого цикла, который почти всегда выходит за пределы допустимого диапазона.   -  person user207421    schedule 12.04.2015
comment
Спасибо, сделаю. Это было только для того, чтобы доказать, что код действительно достиг этой точки.   -  person Jeff B    schedule 12.04.2015


Ответы (1)


Я считаю, что проблема здесь является результатом следующего:

  1. BufferedReader.ready() возвращает true, если есть какие-либо символы, доступные для чтения. Это не гарантирует, что среди них есть какие-либо возвраты каретки. (документы)
  2. BufferedReader.readLine() ищет возврат каретки для завершения строки. Если он не найден, он блокируется.
  3. BufferedWriter.write() не записывает автоматически завершающий возврат каретки.

Чтобы проверить, действительно ли это проблема, замените эту строку в runCommand():

in.write(reader.nextLine());

с:

in.write(reader.nextLine() + "\n");
person radiaph    schedule 12.04.2015
comment
Я мог бы поклясться, что проверял это... Это действительно было проблемой. Спасибо! - person Jeff B; 12.04.2015