I am using a ThreadPoolExecutor to send messages to a native application. The method is in the code pasted below. When I run the method with a test harness, the code works fine. But, when I run with my application, which has a lot of logging and other stuff going on, the worker threads initiated by the ThreadPoolExecutor lock up after a couple of successful executions. I have also pasted stack traces for a few threads.
It looks like one of the worker threads deadlocks on the native readBytes call, and other worker threads are forced to wait forever. Could there be some conflict between the native readBytes and all of the logging that is going on (log4j/apache.commons.logger)?
When I comment out the input stream from the method above, the method works without any failures, so I think it has something to do with the IO.
Also, when I try ping istead of my test .bat file, the IO succeeds (which is much more complext than the IO from my test .bat file).
Java 5 Javadoc for java.lang.Process object states that there are problems for various types of executions:
The methods that create processes may not work well for special processes on certain native platforms, such as native windowing processes, daemon processes, Win16/DOS processes on Microsoft Windows, or shell scripts. The created subprocess does not have its own terminal or console. All its standard io (i.e. stdin, stdout, stderr) operations will be redirected to the parent process through three streams (getOutputStream(), getInputStream(), getErrorStream()). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.
Any chance your process is writing to its error out? That could run into that buffer size problem because you're not reading that stream. If you read the stdout and errout streams in separate threads you can keep up with them and not block the process.
A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
Originally posted by Mike Broadbear: ....Wish I knew why this was such an issue. ...Mike
I believe it is because: one of the worker threads deadlocks on the native readBytes call
The "standard" input stream ... corresponds to keyboard input or another input source specified by the host environment or user.
So: java.io.FileInputStream.readBytes(Native Method) appears to be hanging (to me) .... Thread.interrupt() won't interrupt stdInput.readLine() and commenting out the input stream makes it work, so consistent with earlier work I did I suspect that the underlying implementation is calling into 16-bit single threaded code.
That will not work like Gigabit Switches / Routers.
"The differential equations that describe dynamic interactions of power generators are similar to that of the gravitational interplay among celestial bodies, which is chaotic in nature."
Joined: Jan 14, 2002
I am not reading stderr, although I was at one point, and received similar behavior. If I run the stdout read in a separate thread, I understand the main thread will continue execution (all calls to this method are done with worker threads anyway), but won't the new tread eventually block all future attempts to read stdout?
Yes, it would be interesting to know what is causing the deadlock, i.e. java thread requests native resource and needs to call back to a java resource that is already blocked by a subsequent java thread waiting to call the native resource... My testing worked fine when calls to the external application were sent sequentially, and there was no logging enabled, but in the context of the greater application, the readbytes deadlocks after a few tries.
From what you describe, it does seem like it could be blocking while saiting for you to read the error stream. An easy way to do this is to use ProcessBuilder rather than Runtime.exec(). You can call redirectErrorStream(true) to send error messages to the same stream as regular output - then you don't need to bother making a separate thread to read it; it's all being written to the same place.
Or you can start a new, separate thread to read the error stream, as suggested...
[Mike]: but won't the new tread eventually block all future attempts to read stdout?
I don't see why. The new thread should last as long as the process has an error stream to read. Once the process ends, the error stream will close, and your new thread will terminate. That shouldn't have any effect on any other processes or threads.
Another possible problem is that the process might be blocking waiting for input from you - which you would provide be writing to the process' OutputStream. You would need to know what this bat file does - does it require any user input?
Note that by calling readLine(), you're making the reader block until it can read a full line, with line terminator. Unfortunately if the program has printed a question like "Continue (y/n)?" and has not put a line terminator at the end, your program will continue blocking while waiting for your response, without printing out the question for you. Which would have been a vital clue as to what is going on, yes? But it won't print until the process prints a line separator or ends, and neither of those will happen until you answer the question (which you can't see). I recommend that instead of using readLine(), you simply read whatever chars they can give you:
This way you should get info on any partial lines that are written, including prompts for input.