When creating sub-processes in java using Runtime.exec(), I am aware that I have to fill the input/drain the output streams to prevent blocking of the subprocess.
Interestingly, the javadoc of Process states a little bit more:
...failure to promptly write the input stream or read the output stream of
the subprocess may cause the subprocess to block, and even deadlock.
I am wondering that in this situation the subprocess can also deadlock!
Questions:
1. Under which conditions does it deadlock?
2. Why does it deadlock?
3. Can you provide a short example program which shows this deadlock?
4. Is this deadlock a bug in the OS?
Deadlock can occur due to limited buffer sizes when the parent tries to send too much data to the input stream of its child before reading any of the output.
Consider this code:
For small values for
lines, it will work fine; all oftr‘s output can fit in the OS buffer before we start reading it. However, for large values (>10000 ought to be sufficient), the OS buffer will fill up; within thetrcommand, calls towritewill block, waiting for the buffer to be drained, and in turn, the buffer that the Java code is writing to will fill up (becausetris be blocked, preventing it from reading from its input), in turn blocking our calls toout.write, leading to a deadlock where both processes are waiting to write into full buffers that aren’t being actively read from.This deadlock is not a bug in the OS, as limited buffer sizes for inter-process communication are a deliberate design decision. The alternative (unlimited buffer sizes) has some downsides:
As an aside, deadlock can also occur due to in-process buffers. Suppose that, to attempt to address the deadlock above, we changed our Java code to write one line, then read one line, alternatingly. However, it’s common for Linux processes to not flush after every line when they’re not writing directly to a terminal. So
trmight read a line, and write it to its libc output buffer, and than block waiting for the next line to be written–and our Java code will block waiting fortrto output a line.