Kill both processes at the same time - java

I have an assignment where I must create two instances of a process and the other process must terminate when one of them is terminated. I can only do this when I close the first process created, does this means that created processes have some kind of hierarchy, even though they are both children of the same process?
Thanks in advance.
ProcessBuilder pb = new ProcessBuilder(args);
Process proc_1 = pb.start();
Process proc_2 = pb.start();
System.out.println("Child is running...wait for child to terminate");
int exitValue_1 = proc_1.waitFor();
System.out.println("Child_1 finished with exit value -> " + exitValue_1);
if(exitValue_1==0) proc_2.destroy();
int exitValue_2 = proc_2.waitFor();
System.out.println("Child_1 finished with exit value -> " + exitValue_2);
if(exitValue_2==0) proc_1.destroy();

does this means that created processes have some kind of hierarchy,
No. It's just the way you wrote your code. You are blocking until the first process exits and unfortunately if the second process exits first your code has no way of knowing this.
Since Java is not providing you with a "waitForEitherProcess" method, I think you will need to do a polling loop checking the status of the process. Periodically invoke exitValue on each process then sleep for a few milliseconds. If exitValue returns an int, the process has terminated. If it throws an exception it has not. Use this to decide which process has exited and which needs to be killed.

Process#exitValue will throw a IllegalThreadStateException if the process has not yet exited, you could exploit this.
ProcessBuilder pb = new ProcessBuilder(args);
Process proc_1 = pb.start();
Process proc_2 = pb.start();
boolean running = true;
while (running) {
try {
int exitValue = proc_1.exitValue();
System.out.println("Child_1 finished with exit value -> " + exitValue);
if(exitValue==0) {
proc_2.destroy();
running = false;
break;
}
} catch (IllegalThreadStateException exp) {
}
try {
int exitValue = proc_2.exitValue();
System.out.println("Child_2 finished with exit value -> " + exitValue);
if(exitValue==0) {
proc_1.destroy();
running = false;
break;
}
} catch (IllegalThreadStateException exp) {
}
}

Related

Why in order to execute an external code I have to re-run the main application? [duplicate]

I have the next code:
Process p = Runtime.getRuntime().exec(args);
and I want my program to wait for the Runtime.getRuntime().exec(args); to finish cause it last 2-3sec and then to continue.
Ideas?
use Process.waitFor():
Process p = Runtime.getRuntime().exec(args);
int status = p.waitFor();
From JavaDoc:
causes the current thread to wait, if necessary, until the process represented by this Process object has terminated. This method returns immediately if the subprocess has already terminated. If the subprocess has not yet terminated, the calling thread will be blocked until the subprocess exits.
Here is a sample code:
Process proc = Runtime.getRuntime().exec(ANonJava.exe#);
InputStream in = proc.getInputStream();
byte buff[] = new byte[1024];
int cbRead;
try {
while ((cbRead = in.read(buff)) != -1) {
// Use the output of the process...
}
} catch (IOException e) {
// Insert code to handle exceptions that occur
// when reading the process output
}
// No more output was available from the process, so...
// Ensure that the process completes
try {
proc.waitFor();
} catch (InterruptedException) {
// Handle exception that could occur when waiting
// for a spawned process to terminate
}
// Then examine the process exit code
if (proc.exitValue() == 1) {
// Use the exit value...
}
You can find more on this site: http://docs.rinet.ru/JWP/ch14.htm

How to get the output from a process and set a timeout?

How can I obtain a process' output while setting a timeout value?
I am currently using Apache Commons IO utils to create a string from the process' standard and error outputs.
The code below, as is (with the comments), works fine for processes that terminate. However, if the process doesn't terminate, the main thread doesn't terminate either!
If I uncomment out the commented code and instead comment out process.waitfor(), the method will properly destroy non terminating processes. However, for terminating processes, the output isn't properly obtained. It appears that once waitFor is completed, I cannot get the process' input and error streams?
Finally, if I attempt to move the commented section to where process.waitFor() currently is, remove process.waitFor() and uncomment the commented section, then for non terminating processes, the main thread also won't stop. This is because the process.waitFor(15, ...) will never be reached.
private static Outputs runProcess(String command) throws Exception {
Process process = Runtime.getRuntime().exec(command);
// if (!process.waitFor(15, TimeUnit.SECONDS)) {
// System.out.println("Destroy");
// process.destroy();
// }
// Run and collect the results from the standard output and error output
String stdStr = IOUtils.toString(process.getInputStream());
String errStr = IOUtils.toString(process.getErrorStream());
process.waitFor();
return new Outputs(stdStr, errStr);
}
As #EJP suggested, You can use different threads to capture the streams or use ProcessBuilder or redirect to a file from your command.
Here are 3 approaches that I feel you can use.
Using different threads for Streams.
Process process = Runtime.getRuntime().exec("cat ");
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);
Future<String> output = newFixedThreadPool.submit(() -> {
return IOUtils.toString(process.getInputStream());
});
Future<String> error = newFixedThreadPool.submit(() -> {
return IOUtils.toString(process.getErrorStream());
});
newFixedThreadPool.shutdown();
// process.waitFor();
if (!process.waitFor(3, TimeUnit.SECONDS)) {
System.out.println("Destroy");
process.destroy();
}
System.out.println(output.get());
System.out.println(error.get());
Using ProcessBuilder
ProcessBuilder processBuilder = new ProcessBuilder("cat")
.redirectError(new File("error"))
.redirectOutput(new File("output"));
Process process = processBuilder.start();
// process.waitFor();
if (!process.waitFor(3, TimeUnit.SECONDS)) {
System.out.println("Destroy");
process.destroy();
}
System.out.println(FileUtils.readFileToString(new File("output")));
System.out.println(FileUtils.readFileToString(new File("error")));
Use a redirection operator in your command to redirect Output & Error to a file and then Read from File.
Here is very good blog which explains different ways of handling Runtime.Exec
This is a slightly adjusted version of Kishore Bandi's first solution which uses separate thread to capture output.
It has been simplified, uses no external libraries and have more robust termination code.
Process process = new ProcessBuilder("cat", "file.txt")
.redirectErrorStream(true)
.start();
System.out.println("Output: " + waitForOuput(process, Duration.ofSeconds(10)));
/**
* Waits {#code timeout} time for the output of
* {#code process.getInputStream()}. Returns when the process is terminated.
* Throws on non-zero exit value.
*/
public static String waitForOuput(Process process, Duration timeout) throws InterruptedException, TimeoutException {
ExecutorService pool = Executors.newFixedThreadPool(1);
Future<String> outputFuture = pool.submit(() -> new String(process.getInputStream().readAllBytes()));
pool.shutdown();
try {
String output = outputFuture.get(timeout.toMillis(), TimeUnit.MILLISECONDS);
if (process.exitValue() != 0) {
throw new IllegalStateException("Command " + process.info().command()
+ " returned exit value " + process.exitValue());
}
return output;
} catch (ExecutionException | TimeoutException | InterruptedException ex) {
process.destroyForcibly();
outputFuture.cancel(true);
process.waitFor(1, TimeUnit.SECONDS); // Give process time to die
if (ex instanceof InterruptedException intEx) {
throw intEx;
} else if (ex instanceof TimeoutException timeEx) {
throw timeEx;
} else {
throw new IllegalStateException(ex);
}
}
}

Wait for process to finish before proceeding in Java

Essentially, I'm making a small program that's going to install some software, and then run some basic commands afterwards to prep that program. However, what is happening is that the program starts its install, and then immediately moves on to the following lines (registration, updates, etc). Of course, that can't happen until it's fully installed, so I'd like to find a way of waiting on the first process before running the second. For example,
Main.say("Installing...");
Process p1 = Runtime.getRuntime().exec(dir + "setup.exe /SILENT");
//Wait here, I need to finish installing first!
Main.say("Registering...");
Process p2 = Runtime.getRuntime().exec(installDir + "program.exe /register aaaa-bbbb-cccc");
Main.say("Updating...");
Process p4 = Runtime.getRuntime().exec(installDir + "program.exe /update -silent");
Call Process#waitFor(). Its Javadoc says:
Causes the current thread to wait, if necessary, until the process represented by this Process object has terminated.
Bonus: you get the exit value of the subprocess. So you can check whether it exited successfully with code 0, or whether an error occured (non-zero exit code).
you can use Process.waitFor() method
and the doc says
Causes the current thread to wait, if necessary, until the process
represented by this Process object has terminated. This method returns
immediately if the subprocess has already terminated. If the
subprocess has not yet terminated, the calling thread will be blocked
until the subprocess exits.
If you are running a system command that returns a very long response string, stdin buffer fills up and the process appears to hang. This happened to me with sqlldr. If that appears to be the case then just read from stdin as the process is running.
try {
ProcessBuilder pb = new ProcessBuilder("myCommand");
Process p = pb.start();
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
StringBuffer response = new StringBuffer();
StringBuffer errorStr = new StringBuffer();
boolean alreadyWaited = false;
while (p.isAlive()) {
try {
if(alreadyWaited) {
// read the output from the command because
//if we don't then the buffers fill up and
//the command stops and doesn't return
String temp;
while ((temp = stdInput.readLine()) != null) {
response.append(temp);
}
String errTemp;
while ((errTemp = stdError.readLine()) != null) {
errorStr.append(errTemp);
}
}
Thread.sleep(1000);
alreadyWaited = true;
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.debug("Response is " + response);
logger.debug("Error is: " + errorStr);
}
} catch (IOException e) {
logger.error("Error running system command", e);
}
Include waitFor(). In your case, your code will look something like below.
Main.say("Installing...");
Process p1 = Runtime.getRuntime().exec(dir + "setup.exe /SILENT");
p1.waitFor()
Main.say("Registering...");
Process p2 = Runtime.getRuntime().exec(installDir + "program.exe /register aaaa-bbbb-cccc");
Main.say("Updating...");
Process p4 = Runtime.getRuntime().exec(installDir + "program.exe /update -silent");

java - how to kill a Process if it exceeds an alloted time

I am wondering what the best way is to detect/kill a process if it exceeds a predefined time. I know an old way was to use the watchdog/timeoutobserver class from the ant package. But this is deprecated now, so I am wondering how it should be done now?
Here is the code I have which uses watchdog:
import org.apache.tools.ant.util.Watchdog;
import org.apache.tools.ant.util.TimeoutObserver;
public class executer implements TimeoutObserver {
private int timeOut = 0;
Process process = null;
private boolean killedByTimeout =false;
public executer(int to) {
timeOut = t;
}
public String executeCommand() throws Exception {
Watchdog watchDog = null;
String templine = null;
StringBuffer outputTrace = new StringBuffer();
StringBuffer errorTrace = new StringBuffer();
Runtime runtime = Runtime.getRuntime();
try {
//instantiate a new watch dog to kill the process
//if exceeds beyond the time
watchDog = new Watchdog(getTimeout());
watchDog.addTimeoutObserver(this);
watchDog.start();
process = runtime.exec(command);
//... Code to do the execution .....
InputStream inputStream = process.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(inputStreamReader);
while (((templine = bufferedReader.readLine()) != null) && (!processWasKilledByTimeout)) {
outputTrace.append(templine);
outputTrace.append("\n");
}
this.setStandardOut(outputTrace);
int returnCode = process.waitFor();
//Set the return code
this.setReturnCode(returnCode);
if (processWasKilledByTimeout) {
//As process was killed by timeout just throw an exception
throw new InterruptedException("Process was killed before the waitFor was reached.");
}
} finally {
// stop the watchdog as no longer needed.
if (aWatchDog != null) {
aWatchDog.stop();
}
try {
// close buffered readers etc
} catch Exception() {
}
//Destroy process
// Process.destroy() sends a SIGTERM to the process. The default action
// when SIGTERM is received is to terminate, but any process is free to
// ignore the signal or catch it and respond differently.
//
// Also, the process started by Java might have created additional
// processes that don't receive the signal at all.
if(process != null) {
process.destroy();
}
}
public void timeoutOccured(Watchdog arg0) {
killedByTimeout = true;
if (process != null){
process.destroy();
}
arg0.stop();
}
}
}
Any help would be greatly appreciated as I am a bit lost. I am trying to take this up to Java 7, but I am not uptodate with the best way to kill it if it hangs beyond the alloted time.
Thanks,
try
final Process p = ...
Thread t = new Thread() {
public void run() {
try {
Thread.sleep(1000);
p.destroy();
} catch (InterruptedException e) {
}
};
};
p.waitFor();
t.interrupt();
Theoretically Thread has method stop() that totally kills the thread. This method is deprecated since java 1.1 because it may cause resources leak. So, you are really not recommended to use it.
The "right" solution is to implement your thread so that they can gracefully exit when receiving a special "signal". You can use "interruption" mechanism: your watchdog should call "interrupt()" of thread that exceeds the time limit. But thread should call isInterrupted() itself and exit if it is interrupted. The good news is that method like sleep() and wait() already support this, so if your thread is waiting and you interrupt it from outside it InterruptedException will be thrown.
I have written a set of ExecutorServices that will cancel processes after they have been given a certain period of time to execute. This code has been checked into GitHub.
The class to use to create the ExecutorService is CancelingExecutors. There are two main classes:
CancelingListeningExecutorService allows you to specify the timeout for each passed Callable
FixedTimeoutCancelingListeningExecutorService is configured to use a single timeout for all Callables
If you just concern about WatchDog itself is deprecated, it is nothing more difficult for you to make use of TimerTask, and do the process.destroy() after a period of time.

What is a process_reaper thread in Java?

I'm getting hundreds of these process_reaper threads that build up over time in my application. Anyone have any idea what these may be? They seem to be in my use of Runtime.exec() however I'm destroying my process in a finally statement but they still show up
screen shot:
http://www.dropmocks.com/mBxM5
Process proc = null;
String line;
try {
logger.info("Trying to execute command " + Arrays.asList(command).toString().replace(",", ""));
proc = Runtime.getRuntime().exec(command);
} catch (IOException e) {
logger.info("IOException while trying to execute " + command);
return false;
} finally {
if(proc != null) {
proc.destroy();
}
}
I haven't seen this one myself so I searched a little; it seems a process reaper is related to the Linux kernel process management and is a daemon thread. It maintains the process state so that resources can be freed/released/collected on process termination and so on. This resource might help you. There is a mention on reapers in the final parts.
you must call process.waitFor() after exec and before destory (asy action)

Categories

Resources