import subprocess, sys, time import os import threading code3 = '; '.join(( 'import os, time, sys', 'print("process 3: pid", os.getpid(), file=sys.stderr)', 'print("process 3: stdout", os.fstat(sys.stdout.fileno()), file=sys.stderr, flush=True)', 'time.sleep(5)', 'print("process 3: exit", file=sys.stderr, flush=True)', )) args3 = [sys.executable, '-c', code3] code2 = '; '.join(( 'import subprocess, os, sys', 'print("process 2: pid", os.getpid(), file=sys.stderr)', 'print("process 2: stdout", os.fstat(sys.stdout.fileno()), file=sys.stderr)', 'args = %r' % args3, 'popen=subprocess.Popen(args)', # this code never completes since process 1 kills process 2 'popen.wait()', )) args2 = [sys.executable, '-c', code2] popen = subprocess.Popen(args2, stdout=subprocess.PIPE) print("process 1: pid", os.getpid()) print("process 1: process 2 spawned (pid %s)" % popen.pid) print("process 1: stdout pipe", os.fstat(popen.stdout.fileno())) def kill(popen): # wait until communicate() is running time.sleep(1) print("process 1 (thread): kill process 2 (pid %s)" % popen.pid) popen.kill() print("process 1 (thread): close process 2 stdout pipe (fd %s)" % popen.stdout.fileno()) popen.stdout.close() t = threading.Thread(target=kill, args=(popen,)) t.start() start_time = time.monotonic() print("process 1: communicate with process 2 (pid %s) ..." % popen.pid) popen.communicate() dt = time.monotonic() - start_time print("process 1: communicate with process 2 (pid %s) ... done in %.1f sec" % (popen.pid, dt))