Python子进程查杀

Posted

技术标签:

【中文标题】Python子进程查杀【英文标题】:Python subprocess killing 【发布时间】:2011-10-26 16:44:33 【问题描述】:

我在杀死子进程时遇到问题。以下代码用于创建子流程-

  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() 没有杀死我需要杀死的进程。我使用>> ps aux 在 unix 上检查了这一点。我还编写了我的程序来输出启动和终止 PID,以便我可以使用ps aux 检查它们。我发现我需要杀死的进程距离p.pid 有 6 个 PID,我尝试杀死像 os.kill((p.pid)+6,signal.SIGKILL) 这样的进程,它正在工作并停止正确的进程。但我不想那样做,因为有可能导致不同的子进程被杀死。我正在提供有关我的问题的更多详细信息-

我在这里使用的队列包含我之前所说的命令。命令是这样的-

    echo "Hello"|festival --tts

Festival 是 unix 中的语音合成器,festival --tts 从文件中获取用户输入。我正在向音乐节发送"Hello",它正确地说出了这些话。但是执行上述命令的进程p 正在杀死echo 而不是festival。所以请帮我杀死特定的(节日)进程。

【问题讨论】:

“stopPressed”和“stopprcs”不应该是同一个变量吗? @aid 说了什么。但也仍然怀疑是线程问题。 对不起,我更改了变量的名称以使其更易于阅读。我现在已经做出改变了。 【参考方案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会创建一个同名的局部变量,而不是访问全局变量。 是的,我确实明确表示它是全球性的。但是 kill() 不起作用。【参考方案2】:

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

【讨论】:

【参考方案3】:

正如@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() 没有杀死正确的进程。我将更新我的帖子以反映这一点。 万一,您是否使用裸异常捕获代码中的所有异常,例如 try: somecode() except: somehanding() 您应该始终使用 except Exception: ... 如果您想要捕获所有,因为一个裸的 except 也会捕获一个 SIGINT。【参考方案4】:

由于节日程序在 UNIX 中,我们可以使用 preexec_fn。 Festival 正在创建自己的子进程,这使得杀戮变得更加困难,因此在这种情况下,使用标识所有节日进程的 group 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)

将杀死产生的子进程组。 来源:Working with subprocess

【讨论】:

以上是关于Python子进程查杀的主要内容,如果未能解决你的问题,请参考以下文章

python subprocess模块 监控子进程的2种方式 忙等待和立即返回同时设置子进程超时

Windows 上的 Python 子进程:启动子进程“cmd.exe”并为其提供 bat 文件,停止主进程执行

以与长时间运行的 Python 进程不同的用户身份运行子进程

python子进程模块subprocess详解

为啥 Python 子进程“继承”父进程的线程?

Python [子] 进程向节点 [父] 进程发送消息