4

Let me explain my software. What my software simply does is that it creates 10 threads and assigns a number of tasks to each thread. Each thread then creates a Runtime Process that will start a cmd batch file which in turn will start a program that will telnet to a device (I have about 200 of them) to poll its configuration. Here is the code for my process creation:

Process p1 = java.lang.Runtime.getRuntime().exec("cmd /c  start /b /wait " + batchFile); 
int returnVal = p1.waitFor();

batchFile is the full path of the batch file. Don't get me wrong, the software works fine up to 100% of the execution and it hanged ONLY ONE TIME at about 95%, so I'm trying to find a solution for that. Why it hanged is not my issue now, but rather how to deal with hangups later on..!

Now the problem is that I need to wait for the process to finish because my telnet client will write to a file that I will read later on in the thread; and hence the use of the .waitFor() . My question is how can I get the thread to understand that the external program hanged? In other words, can I give the external program some time limit to finish; and if it does not the thread will kill the process?

Also I have read about reading the error and output streams; however, I don't think it is applicable here, or is it?

Extreme Coders
  • 3,441
  • 2
  • 39
  • 55
  • 1
    *"Also I have read about reading the error and output streams; however, I don't think it is applicable here, or is it?"* Most likely, yes. Consume both of them and display them. – Andrew Thompson Jan 23 '13 at 15:42
  • TBH, I have not tried cause I am assuming that they will not be of use because of the `waitfor()`. Won't it be called only once? – mohammed lalalala Jan 23 '13 at 15:46

1 Answers1

3

Also I have read about reading the error and output streams; however, I don't think it is applicable here, or is it?

Almost certainly yes, it is applicable. Try using ProcessBuilder instead of Runtime.exec and read all the output before calling waitFor. For example (exception handling omitted, in particular waitFor may throw InterruptedException before the process actually exited)

    ProcessBuilder pb = new ProcessBuilder(
        "cmd", "/c", "start", "/b", "/wait", batchFile);
    pb.redirectErrorStream(true);
    Process p = pb.start();
    IOUtils.closeQuietly(p.getOutputStream());
    IOUtils.copy(p.getInputStream(), System.out);
    // or alternatively throw away the output using
    // IOUtils.copy(p.getInputStream(), NullOutputStream.NULL_OUTPUT_STREAM);
    IOUtils.closeQuietly(p.getInputStream());
    int returnVal = p.waitFor();

(IOUtils and NullOutputStream are from Apache commons-io).

To answer the actual question in the title, if your process still hangs even after properly reading its output, you may need to use p.destroy() to forcibly terminate the process. You could define a timer task something like

    public class TimeoutProcessKiller extends TimerTask {
      private Process p;
      public TimeoutProcessKiller(Process p) {
        this.p = p;
      }

      public void run() {
        p.destroy();
      }
    }

and then do

    // single shared timer instance
    Timer t = new Timer();

    // for each device
    Process p = pb.start();
    TimerTask killer = new TimeoutProcessKiller(p);
    t.schedule(killer, 30000);
    // ... read output stream as before ...
    int returnVal = p.waitFor();
    killer.cancel();

This will cause the process to be killed if it has been running for more than 30 seconds (adjust the schedule call to change the timeout).

Nowhere Man
  • 19,170
  • 9
  • 17
  • 42
Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
  • Thank you, it was exactly what I was looking for to avoid an ANR in Android (after 5 seconds), so I've changed to t.schedule(killer, 4500); – Christian Oct 07 '17 at 07:08
  • With Java 8, it's also possible to use waitFor(long timeout, TimeUnit unit) which returns a boolean. (API 26 minimum in Android) – Christian Oct 07 '17 at 07:14
  • do we really have to call int returnVal = p.waitFor(); at the end? can someone clarify if we have used t.schedule(killer, 30000); then p.waitFor() at the end seems redundant. – user593029 May 10 '19 at 01:47