2013-10-09 3 views
2

Я запуска приложения CMD, который выводит в System.out через этот SyncPipe Runnable:конец нити, что застрял в InputStream.read() петли

public class SyncPipe implements Runnable { 

    private final InputStream is; 
    private final OutputStream os; 

    public SyncPipe(InputStream is, OutputStream os) { 
     this.is = is; 
     this.os = os; 
    } 

    public void run() { 
     try { 
      final byte[] buffer = new byte[1024]; 
      for (int length = 0; (length = is.read(buffer)) != -1;) 
       os.write(buffer, 0, length); 
      System.out.print("stopped"); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
    } 

} 

я начала RunIt с cmd = "C:/bin/read.exe -f D:/test.jpg"

private class RunIt implements Runnable { 

    public int p; 
    public String cmd; 

    public RunIt (int p, String cmd) { 
     this.p = p; 
     this.cmd = cmd; 
    } 

    public void run() { 
     ProcessBuilder pb = new ProcessBuilder("cmd"); 
     try { 
      process = pb.start(); 
      (new Thread(new SyncPipe(process.getErrorStream(), System.err))).start(); 
      (new Thread(new SyncPipe(process.getInputStream(), System.out))).start(); 
      OutputStream out = process.getOutputStream(); 
      out.write((cmd + "\r\n").getBytes()); 
      out.flush(); 
      out.close(); 

      try { 
       process.waitFor(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 

      println("Stopped using %d.", p); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 
    } 

} 

Мой вопрос сейчас: Как я могу сделать (new Thread(new SyncPipe(process.getErrorStream(), System.err))) die? Предоставляя SyncPipe логическую переменную stop, устанавливая ее true во время выполнения и проверяя ее с помощью for (int length = 0; (length = is.read(buffer)) != -1 && !stop;), не удалось сделать трюк.

Большое спасибо.


Я закончил работу вокруг этого @Gray. Он работает сейчас:

public void run() { 
    try { 
     final byte[] buffer = new byte[1024]; 
     do 
      if (is.available() > 0) { 
       int length = is.read(buffer); 
       if (length != -1) 
        os.write(buffer, 0, length); 
       else 
        stop = true; 
      } 
     while (!stop); 
    } catch (Exception ex) { 
     ex.printStackTrace(); 
    } 
} 

ответ

1

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

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

+0

Вы правы, но он все равно должен закрыть потоки - по крайней мере, потоки фона не заканчивались в Unix без специального закрытия в моей тестовой программе. – Gray

+0

Оба вы правы ... Я убил базовый процесс через 'Runtime.getRuntime(). Exec (" taskkill/f/pid "+ pid);' и моя старая реализация также прекрасно закрывается. Но я определенно должен закрыть потоки. В любом случае: Большое спасибо. – dotwin

+0

@Gray Конечно, ему нужно закрыть потоки, когда он читает EOS на них. Я не сказал иначе. – EJP

1

Мой вопрос теперь: Как я могу сделать (новый Thread (новый SyncPipe (process.getErrorStream(), System.err))) умереть?

Вам нужно будет закрыть входной поток из-под него, я верю. Я подозреваю, что он заблокирован в режиме чтения и без значения переменной stop (даже если правильно volatile) получит разблокированный поток для чтения.

Вы будете нуждаться, чтобы сделать что-то вроде:

InputStream is = process.getInputStream(); 
InputStream es = process.getErrorStream(); 
... 
is.close(); 
es.close(); 

код будет выглядеть примерно следующим образом. Я не уверен, возвращается ли ваш звонок waitFor() или нет.

InputStream is = process.getInputStream(); 
InputStream es = process.getErrorStream(); 
(new Thread(new SyncPipe(es, System.err))).start(); 
(new Thread(new SyncPipe(is, System.out))).start(); 
try { 
    OutputStream out = process.getOutputStream(); 
    out.write((cmd + "\r\n").getBytes()); 
    out.flush(); 
    out.close(); 
    try { 
     process.waitFor(); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} finally { 
    is.close(); 
    es.close(); 
} 

Другой ответ может быть использование метода available() на InputStream, так что вы можете петлю и проверить stop флаг. См этот ответ: https://stackoverflow.com/a/1089079/179850

+0

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

+0

Хорошо, попробуем сейчас ... Спасибо. – dotwin

+0

Huh. Это подходит для меня. Ваш процесс останавливается или вы пытаетесь остановить «SyncPipe» из другого потока? – Gray

1

InputStream#read() состояний

Этот метод блоки до тех пор, входные данные не доступны, конец потока обнаруживается, или исключение.

Итак, когда вы идете в вашу for петлю

for (int length = 0; (length = is.read(buffer)) != -1;) 
    os.write(buffer, 0, length); 

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

Если цель SyncPipe состоит в том, чтобы передать содержимое вашим стандартным потокам вывода/ошибок, почему вы хотите остановить запуск Thread?

+0

Мне нужно все, чтобы в какой-то момент остановиться. «C:/bin/read.exe» не закрывается красиво (я всегда закрываю его с помощью ctrl + c при выполнении его в командной строке). Закрытие 'process' с' .destroy() 'не выполняет эту работу. Я бы хотел, чтобы все закрылось, когда мне это нужно. 'out.write ((char) 3 +" \ r \ n "). getBytes());' также не помогает. Я подозреваю, что потоки SyncPipe Threads все ожидают. – dotwin

+0

@dotwin Вам нужно будет закрыть потоки самостоятельно, вызывая 'close()'. –

+0

Попробуем сейчас, спасибо. – dotwin

Смежные вопросы