Normally, you don't need to do anything -- the current subprocess
implementation maintains a global list of active unreferenced Popen
instances and when a new Popen object is created, this list is enumerate and .poll()
is called for each process.
Thus if you don't have a reference to the subprocess; it is waited for you automatically (and if you do have a reference then call .wait()
yourself).
If child processes are created by other means then you could call os.waitpid()
to collect exit statuses of dead subprocesses on Unix:
while True:
try:
pid, status = os.waitpid(-1, os.WNOHANG)
except ChildProcessError:
# No more child processes exist
break
else:
assert pid, "child process is still alive"
On POSIX.1-2001 systems, you could call signal(SIGCHLD, SIG_IGN)
to reap children automatically instead.
If you want to kill all children (send a signal) when a parent dies; you could use prctl
PR_SET_PDEATHSIG
on Linux. It works if the parent dies for any reason i.e., it works even if the parent is killed by SIGKILL
.
psutil
from @ali_m' answer is a portable solution:
#!/usr/bin/env python
import gc
import subprocess
import time
import psutil
for _ in range(10):
subprocess.Popen(['sleep', '1']) # no reference
time.sleep(2) # wait until they are dead
gc.collect() # run garbage collection, to populate _active list
subprocess.Popen(['sleep', '1']) # trigger _cleanup()
for i in range(2):
for child in psutil.Process().children(): # immediate children
print(child, child.status())
if i == 0:
time.sleep(2)
Output
psutil.Process(pid=31253, name='sleep') sleeping
psutil.Process(pid=31253, name='sleep') zombie
Note:
psutil
shows only one zombie process, the rest are reaped in the last Popen()
call
psutil
provides a protection against pid
reuse but it is not 100% reliable in all cases -- check whether it is enough in your case (otherwise, use one the methods above that do not rely on child's pid
).