Hi all -- I'm having an issue trying to execute a shell command to determine architecture type (uname -m on Linux and Mac). For the record I have read both of the following links thoroughly, and several times:
When Runtime.exec() won't: http://www.javaworld.com/jw-12-2000/jw-1229-traps.html
Five Common java.lang.Process Pitfalls: http://kylecartmell.com/?p=9
The problem seems to be some sort of race condition with the StreamGobblers, which are streams for STDOUT and STDERR. I process the streams and invoke waitFor() and then I package up the return code and the output from the two streams into an Object array. However, it seems like by the time it's returning the Object array, the streams haven't been properly flushed. Just because the initial thread has finished and received a return value doesn't mean that the two gobbler threads have finished flushing their data out...does it?
I'm looking at the first article there and I would assume they need to call join() on the StreamGobblers before invoking p.waitFor(). It seems to resolve the problem for me. Am I wrong about this? If I don't call join() on those threads then I don't see any output in my caller method unless I introduce some sort of delay in the callee, such as stepping through the debugger, or adding in a call to Thread.sleep() right before invoking p.waitFor().
This article is 12 years old so I would expect that someone would have corrected them by now. I can't honestly believe nobody ever noticed this until now, especially with all of the comments there saying that the article saved them. Am I just missing something here? It sure seems like they need to call join() on the gobblers. See "Listing 4.5 GoodWindowsExec.java" on page 4 (http://www.javaworld.com/jw-12-2000/jw-1229-traps.html?page=4) and then compare that to my proposed changes below:
// a bunch of setup stuff above here but not necessary for this example
Runtime rt = Runtime.getRuntime();
System.out.println("Execing " + cmd[0] + " " + cmd[1]
+ " " + cmd[2]);
Process proc = rt.exec(cmd);
// any error message?
StreamGobbler errorGobbler = new
StreamGobbler(proc.getErrorStream(), "ERROR");
// any output?
StreamGobbler outputGobbler = new
StreamGobbler(proc.getInputStream(), "OUTPUT");
// kick them off
errorGobbler.start();
outputGobbler.start();
errorGobbler.join(); // NEED TO ADD THIS LINE
outputGobbler.join(); // NEED TO ADD THIS LINE
// any error???
int exitVal = proc.waitFor();
System.out.println("ExitValue: " + exitVal);
// I return an object array like this to my caller:
Object[] ret = new Object[3];
ret[0] = new Integer(exitVal);
ret[1] = outputGobbler.getOutputStream(); // I implemented getOutputStream in my version to return a String
ret[2] = errorGobbler.getOutputStream(); // rather than printing everything with System.out.println()
return ret;
} catch (Throwable t)
{
t.printStackTrace();
}
}
}
Edited by: gamblor01 on Dec 18, 2012 3:42 PM
Edited by: gamblor01 on Dec 18, 2012 3:43 PM
Edited by: gamblor01 on Dec 18, 2012 3:46 PM