Python 子进程终止
我遇到了一个问题,就是无法结束子进程。下面这段代码是用来创建子进程的:
while(not myQueue.empty()):
p=Popen(myQueue.get(),shell=True,stdin=PIPE,stderr=PIPE)
我通过不断循环,直到队列(里面有命令)为空来创建进程。变量 p 是全局的,类型是 Popen。尽管命令已经完成了它应该做的事情,但我在停止按钮上遇到了问题,它没有像我预期的那样停止进程。
停止按钮的代码如下:
stop=Button(textBoxFrame,text="Stop",width=5,command=stopAll)
stop.grid(row=1,column=4)
上面的停止按钮会调用 stopAll 方法,这个方法会结束当前的子进程 p。
def stopAll():
p.kill()
注意:没有错误、异常或编译问题。
更新:问题在于 p.kill()
并没有结束我想要结束的进程。我用 unix 检查了这一点,使用了 >> ps aux
。我还让我的程序输出启动和结束的进程 ID(PID),这样我可以用 ps aux
来检查它们。我发现我需要结束的进程距离 p.pid
有 6 个 PID 的差距,我尝试用 os.kill((p.pid)+6,signal.SIGKILL)
来结束那个进程,这样是有效的,能够停止正确的进程。但我不想这样做,因为这样可能会导致其他子进程被错误地结束。我会提供更多关于我问题的细节:
我这里使用的队列包含了命令,正如我之前提到的。命令大致是这样的:
echo "Hello"|festival --tts
Festival 是一个在 unix 上的语音合成器,festival --tts
从文件中获取用户输入。我把 "Hello"
传给 festival,它能正确地说出这些话。但是,p
这个执行上述命令的进程却结束了 echo
而不是 festival
。所以请帮我结束特定的(festival)进程。
4 个回答
正如@aid提到的,如果你不明确把这个句柄设置为全局的,你就无法为其他人更改它。试试这个,替代你的stopAll函数。
def stopAll():
global stopPressed
stopPressed=True
我建议与其去搞全局变量,不如创建一个类,比如说:
class GuiController(object):
# if you want the stopPressed to be a static variable accross all
# GuiController instances uncomment the next line and comment out the __init__
#stopPressed = False
def __init__(self):
self.stopPressed=False
def main(self):
while(not myQueue.empty()):
p=Popen(myQueue.get(),shell=True,stdin=PIPE,stderr=PIPE)
while(p.returncode==None):
if(stopPressed==True):
p.kill()
break
self.stopPressed=False
def stopAll(self):
self.stopPressed=True
我怀疑你可能遇到问题是因为你没有在stopAll()这个函数里把stopPressed声明为全局变量。比如说,
>>> fred = '20'
>>> def updateFred(age):
... fred=age
>>> updateFred(40)
>>> fred
'20'
>>> def updateFred(age):
... global fred
... fred=age
>>> updateFred(40)
>>> fred
40
也许在stopAll()的开头加上'global stopPressed'会有帮助?
因为这个节日程序是在UNIX系统上运行的,所以我们可以使用preexec_fn这个功能。Festival程序会自己创建一些子进程,这让我们很难结束它们。因此,这里我们可以利用一个组ID,它可以识别所有Festival相关的进程,这样就能解决这个问题。我们可以用下面的代码来创建一个进程组-
while(not myQueue.empty()):
p=Popen(myQueue.get(),shell=True, stdin=PIPE,preexec_fn=os.setsid)
stopAll现在有了以下代码,用于结束由全局变量p指向的一组子进程-
os.killpg(os.getpgid(p.pid), signal.SIGKILL)
这段代码会结束所有被创建的子进程。
来源:处理子进程