为了避免轮询子进程的状态,可以
SIGCHLD在Unix上使用signal。要将其与tkinter的事件循环结合使用,可以使用self-
pipe技巧。它还解决了可能的tkinter
+信号问题,而无需定期唤醒事件循环。
#!/usr/bin/env python3import loggingimport osimport signalimport subprocessimport tkinterinfo = logging.getLogger(__name__).infodef on_signal(pipe, mask, count=[0]): try: signals = os.read(pipe, 512) except BlockingIOError: return # signals have been already dealt with # from asyncio/unix_events.py #+start # Because of signal coalescing, we must keep calling waitpid() as # long as we're able to reap a child. while True: try: pid, status = os.waitpid(-1, os.WNOHANG) except ChildProcessError: info('No more child processes exist.') return else: if pid == 0: info('A child process is still alive. signals=%r%s', signals, ' SIGCHLD'*(any(signum == signal.SIGCHLD for signum in signals))) return #+end # you could call your callback here info('{pid} child exited with status {status}'.format(**vars())) count[0] += 1 if count[0] == 2: root.destroy() # exit GUIlogging.basicConfig(format="%(asctime)-15s %(message)s", datefmt='%F %T', level=logging.INFO)root = tkinter.Tk()root.withdraw() # hide GUIr, w = os.pipe2(os.O_NonBLOCK | os.O_CLOEXEC) signal.set_wakeup_fd(w) root.createfilehandler(r, tkinter.READABLE, on_signal)signal.signal(signal.SIGCHLD, lambda signum, frame: None) # enable SIGCHLDsignal.siginterrupt(signal.SIGCHLD, False) # restart interrupted syscalls automaticallyinfo('run children')p = subprocess.Popen('sleep 4', shell=True)subprocess.Popen('sleep 1', shell=True)root.after(2000, p.send_signal, signal.SIGSTOP) # show that SIGCHLD may be deliveredroot.after(3000, p.send_signal, signal.SIGCONT) # while the child is still aliveroot.after(5000, lambda: p.poll() is None and p.kill()) # kill itroot.mainloop()info('done')输出量
2015-05-20 23:39:50 run children2015-05-20 23:39:51 16991 child exited with status 02015-05-20 23:39:51 A child process is still alive. signals=b'x11' SIGCHLD2015-05-20 23:39:52 A child process is still alive. signals=b'x11' SIGCHLD2015-05-20 23:39:53 A child process is still alive. signals=b'x11' SIGCHLD2015-05-20 23:39:54 16989 child exited with status 02015-05-20 23:39:54 No more child processes exist.2015-05-20 23:39:54 done



