Python子进程终止

5

我遇到了杀死子进程的问题。以下代码用于创建子进程:

  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。我还让我的程序输出启动和杀死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)进程。


1
“stopPressed”和“stopprcs”不应该是同一个变量吗? - aid
@aid所说的没错。但我仍然怀疑这是一个线程问题。 - Wissam Youssef
抱歉,我修改了变量的名称以便于阅读。我已经进行了更改。 - Alphaceph
4个回答

1

我怀疑你可能遇到了问题,因为你没有在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'会有帮助?

重点是,在函数中,如果您不将变量声明为全局变量,则 Python 将创建一个同名的局部变量,而不是访问全局变量。 - Dunes
是的,我确实将它明确地声明为全局变量。但是kill()函数没有起作用。 - Alphaceph

0

正如@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

我有类似于你的代码。我现在找到了问题所在,是p.kill()没有杀死正确的进程。我会更新我的帖子以反映这一点。 - Alphaceph
你是否在代码中使用裸的 except 来捕获所有异常,像这样: try: somecode() except: somehanding()如果你想要捕获所有异常,你应该始终使用 except Exception: ... ,因为裸的 except 也会捕获 SIGINT。 - Pykler

0

由于节日程序是在UNIX中运行的,我们可以利用preexec_fn。节日程序正在创建自己的子进程,这使得杀死它们更加困难,因此,在这种情况下,使用标识所有节日进程的组ID将解决问题。我们可以使用以下代码创建一组进程-

   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)

将会结束由父进程创建的所有子进程组。 来源: 使用子进程


0

我认为需要更多的代码。我不确定您如何处理按钮被按下的事件(怀疑是线程问题)。此外,stopprcs不应该包含在第一个循环内而不是外部吗?这可能是一个间距问题(或者问题只是在这里)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接