我需要能够将控制c发送到我开始的新线程。我该怎么做呢我可以启动线程,但是我需要像使用控件c一样在命令行中停止。
from Tkinter import *
import threading # should use the threading module instead!
import Queue
import os
def show1():
os.system('ola_recorder -p MyRecord -i 0')
def show2 ():
os.system('ola_recorder -p MyRecord ')
def stop ():
os.system('^c')
t = threading.Thread(name='Show2', target=show2)
root = Tk()
b = Button(root, text="Show 1", command=lambda: thread.start_new(show1, ()))
b.pack()
b2 = Button(root, text="Show 2", command=lambda: t.start())
b2.pack()
root.mainloop()
答案 0 :(得分:4)
首先,你正在做的事情不起作用:
每次调用os.system
只会调用平台的system
(或某些Windows平台上的_system
)函数,每次都会创建一个全新的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
对象。有关您可以使用它的详细信息,请参阅the docs,但这是一个快速版本:
def stop():
global proc2
try:
sig = signal.CTRL_C_EVENT
except AttributeError:
sig = signal.SIGINT
proc.send_signal(sig)
当您调用stop
时,该过程将被完全杀死,就像它已收到^ C(POSIX)一样,或尽可能接近,就好像它已收到^ C(Windows),{ {1}}调用将返回(带有-2,至少在POSIX上),您的线程也会完成。
最后一点:你几乎不想直接使用wait
模块,也不想重用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()
所有线程。