I reduced a problem I was seeing in my application down into the following test case. In this code, a parent process concurrently spawns 2 (you can spawn more) subprocesses that
After way too much time, I figured it out, after a quote from this post jumped out at me:
See the "I/O on Pipes and FIFOs" section of pipe(7) ("man 7 pipe")
"If all file descriptors referring to the write end of a pipe have been closed, then an attempt to read(2) from the pipe will see end-of-file (read(2) will return 0)."
I should've known this, but it never occurred to me - had nothing to do with Python in particular. What was happening was: the subprocesses were getting forked with open (writer) file descriptors to each others' pipes. As long as there are open writer file descriptors to a pipe, readers won't see EOF.
E.g.:
p1=Popen(..., stdin=PIPE, ...) # creates a pipe the parent process can write to
p2=Popen(...) # inherits the writer FD - as long as p2 exists, p1 won't see EOF
Turns out there's a close_fds
parameter to Popen
, so the solution is to pass close_fds=True
. All simple and obvious in hindsight, but still managed to cost at least a couple eyeballs good chunks of time.