首先,您正在做的事情不起作用的原因是:
每次调用os.system
只调用您平台的system
(或者_system
,在某些 Windows 平台上)函数,每次都会创建一个全新的 shell 进程。因此,您无法做任何事情os.system
来影响另一个呼叫。
如果要将 ^C 发送到任意进程,可以使用os.kill
. 要使其可移植,您必须执行以下操作:
def send_ctrl_c(pid):
try:
sig = signal.CTRL_C_EVENT
except AttributeError:
sig = signal.SIGINT
else:
os.signal(pid, sig)
但是,您需要其他进程的 pid 来执行此操作,并且os.system
不给您。
所以,正确的做法是使用subprocess
模块:
proc2 = None
def show2():
global proc2
proc2 = subprocess.Popen('ola_recorder -p MyRecord', shell=True)
proc2.wait()
由于没有充分的理由在这里使用 shell,你可能最好传递Popen
一个 args 列表,而不是一个字符串,并放弃shell=True
. 当然,不坚持proc2
全局会更干净,但对于这个玩具示例,我将忽略这一点。
无论如何,现在您可以获取 pid 并使用它:
def stop():
send_ctrl_c(proc2.pid)
但是,如果您要这样做,您不妨Popen
直接使用该对象。有关您可以使用它做什么的完整详细信息,请参阅文档,但这里有一个快速版本:
def stop():
global proc2
try:
sig = signal.CTRL_C_EVENT
except AttributeError:
sig = signal.SIGINT
proc.send_signal(sig)
当您调用 时stop
,该进程将被终止,就像它收到一个 ^C (POSIX),或者尽可能接近它收到一个 ^C (Windows),wait
调用将返回(带有 -2,至少在 POSIX 上),您的线程也将完成。
最后一点:您几乎不想thread
直接使用模块,也不想重用threading.Thread
对象。所以,而不是这个:
b = Button(root, text="Show 1", command=lambda: thread.start_new(show1, ()))
… 或这个:
b2 = Button(root, text="Show 2", command=lambda: t.start())
… 做这个:
def start2():
global t2
t2 = threading.Thread(name='Show2', target=show2)
t2.start()
当然,一个非玩具程序应该避免使用全局,并且希望跟踪所有现有线程而不是只跟踪最后一个(如果允许您在后台线程已经运行时单击按钮),并且可能会希望join
在退出时将其所有线程。