为了避免轮询子进程的状态,您可以使用SIGCHLD
Unix 上的信号。要将其与 tkinter 的事件循环结合起来,您可以使用自管技巧 http://cr.yp.to/docs/selfpipe.html。也有解决办法可能的 tkinter + 信号问题 https://mail.python.org/pipermail/tkinter-discuss/2011-January/002737.html无需定期唤醒事件循环。
#!/usr/bin/env python3
import logging
import os
import signal
import subprocess
import tkinter
info = logging.getLogger(__name__).info
def 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 GUI
logging.basicConfig(format="%(asctime)-15s %(message)s", datefmt='%F %T',
level=logging.INFO)
root = tkinter.Tk()
root.withdraw() # hide GUI
r, 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 SIGCHLD
signal.siginterrupt(signal.SIGCHLD, False) # restart interrupted syscalls automatically
info('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 delivered
root.after(3000, p.send_signal, signal.SIGCONT) # while the child is still alive
root.after(5000, lambda: p.poll() is None and p.kill()) # kill it
root.mainloop()
info('done')
Output
2015-05-20 23:39:50 run children
2015-05-20 23:39:51 16991 child exited with status 0
2015-05-20 23:39:51 A child process is still alive. signals=b'\x11' SIGCHLD
2015-05-20 23:39:52 A child process is still alive. signals=b'\x11' SIGCHLD
2015-05-20 23:39:53 A child process is still alive. signals=b'\x11' SIGCHLD
2015-05-20 23:39:54 16989 child exited with status 0
2015-05-20 23:39:54 No more child processes exist.
2015-05-20 23:39:54 done