This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
Question: what can prevent destroy() from destroying a Process object?
I'm modifying a legacy program that runs a child process, which it gets from a call to Runtime.getRuntime().exec(). One requested feature was to stop the process if it hangs. So, I have implemented code to run a timing thread and interrupt this thread if the time expires before this (main) thread is complete. If interrupted, the thread destroys the process. Here's the code:
I've noticed that destroy() does not function instantly; that's why there is a second waitFor() call.
When I run the program with a ridiculously short time limit, the thread will be interrupted and log the messages saying that it is going to destroy the process. But the process completes normally- it even returns an exit code of 0! I should note that this child process is NOT fast. It may take up to a full minute to run, even when destroy() is called after 1 ms or 1 second or 10 seconds after it begins.
My tests (not using this specific child process) work beautifully. I have no problem using destroy() on simple test processes on the Linux box this runs on.
The only hint I can find is from another post on this forum, suggesting that all input needs to be read from the process before it ends. You can see above the odd code where it reads output from the child process, then calls waitFor()- that was in the original legacy code. I added the code that checks for an InterruptedException and destroys it. Could this possibly have anything to do with it? And if so, how can I get around it so I can destroy it?
I tried just interrupting the thread, thinking that would automatically kill the process said thread was running, but that didn't work either.
[Chad]: The only hint I can find is from another post on this forum, suggesting that all input needs to be read from the process before it ends. You can see above the odd code where it reads output from the child process, then calls waitFor()- that was in the original legacy code. I added the code that checks for an InterruptedException and destroys it. Could this possibly have anything to do with it? And if so, how can I get around it so I can destroy it?
Yes, it seems like failing to read the output could cause this problem. Really you need to handle this anytime you run a process that can have any output, even if you're not trying to destroy it. In fact, failure to read the output could be why the process is hanging in the first place. To do this right, you need to read using two separate threads, one for standard output, and one for error output. (Unless you redirect these to be the same stream, which can simplify things.) You need two threads because if one stream fills its buffer while you're trying to read the other stream, the whole process can block up indefinitely. You don't know in advance which one may fill its buffer, so you need to be able to read both independently. You could just ignore everythign you read (since you're trying to destroy the process anyway), but you may well get useful info by printing it somewhere instead.
Alternately, maybe reading these streams has nothing to do with the problems you're seeing. I would suggest you try killing the process from the command line - e.g. with kill -9 on unix. If this works promptly enough, then you can write a script to do this programmatically, and call this script when you want to kill the process. Details of this will depend on your operating system, and what you know about the process you're trying to kill.
"I'm not back." - Bill Harding, Twister
Joined: Mar 25, 2007
Well, I've done more reading, more experimenting, and a great deal of banging my head against the wall. I've made progress, but have another problem.
On my Windows machine, I found that neglecting to read output will cause a process to hang around indefinitely- however, this does NOT prevent the process from being destroyed. Interrupting a thread does not appear to automatically kill the child process; it musy be explicitly destroyed. If I'm incorrect about any of this, please let m know, as that means I made a mistake.
The original problem I had was in the code I showed originally. The code looped until all output from the process was exhausted, and THEN exercised the waitFor() method. So my program only checked to see if it was interrupted on the waitFor() catch block- after the process had completed.
The revised code is as follows:
As suggested, the new ProcessOutputThread class runs as a separate thread, reading output from the process. Here's the class (minus comments, imports, etc)
The method of checking readLine() != null to tell when a process is complete seems odd to me, but that's from the legacy code- and I can't think of a better way.
It works beautifully- on MY machine. But on the Linux server, not so much. When the timer is set to a small amount (100-1000ms, just for testing purposes) and interrupts the main thread (the first chunk of code here), then this throws an IOException from the line containing "processOut.readLine()"
Why would it do this- and only on some machines? What's the best way to get around it?