使用 signal.CTRL_C_EVENT 杀死子进程而不影响主进程

5

如何在不杀死“主进程”的情况下终止子进程?

我有一个只能使用signal.CTRL_C_EVENT终止的子进程。执行标准的os.kill(my_pid, signal.CTRL_C_EVENT)会终止该进程,但也会导致我的主进程死亡,尽管它拥有不同的pid。

我的最终目标是从单元测试中创建子进程,因此我需要该单元测试在通过所有测试后返回sys.exit(0)

child.py

from time

while True:
  print "I am alive"
  time.sleep(0.5)

parent.py

import os
import signal
import subprocess
import time

p = subprocess.Popen(["child.py"], shell=True)
time.sleep(5)
os.kill(p.pid, signal.CTRL_C_EVENT)

print("This line doesn't print because the main thread dies")

::: 更新 :::

我试图在Windows上运行这个程序。移除shell=True似乎没有影响。我在parent.py中看到了一个KeyboardInterrupt错误。

Traceback (most recent call last)    
    File "parent.py", line 23, in <module>
KeyboardInterrupt

以下所有方法都会导致相同的行为

  • os.kill
  • psutil.Process(os.getpid()).children() 发送信号
  • subprocess.call(['taskkill', ...
2个回答

1

我猜你在使用Windows系统。这是一个重要的区别。同时,看起来你正在使用Python2。

在Windows上,os.kill有一些非常奇怪的行为。我建议你不要尝试使用它,除非你想让自己头痛。尝试在父进程中使用psutil

    children = psutil.Process(os.getpid()).children()
    for c in children:
        c.send_signal(signal.CTRL_C_EVENT)
    psutil.wait_procs(children)

或者,您可以调用taskkill

subprocess.call(['taskkill', '/PID', str(child.pid)])

是的,这是在Windows上。两种方法仍然会终止主程序。 - J'e
这两种方法都会结束主进程和子进程吗?这听起来好像并没有真正启动一个新的进程。试试这个:像你现在做的那样同时启动子进程和主进程,但是在它们每一个中添加一个打印语句,打印它们自己的PID。在父进程中,让它也打印出它“认为”的子进程的PID。然后让它们都睡眠足够长的时间,以便您可以查看任务管理器并查看这些PID是否与报告的PID相匹配。 - Z4-tier
尝试摆脱shell=True选项,这个选项在某种程度上非常依赖于平台,可能会产生奇怪的结果。你可能需要更改调用popen的方式,以给出Python解释器可执行文件的完整路径,然后是child.py文件的完整路径。 - Z4-tier
我在我的初始问题中添加了一个:::update::: - J'e

0

您可以尝试将字节0x03发送到子进程的标准输入(stdin)。这是用于指示Ctrl+C信号的字节。


也许在Windows中会有所不同,但在UNIX中,信号并不是通过标准I/O流传递的。内核用于传递信号的机制取决于发送的信号类型、程序配置为处理某些信号的方式(如果有)、以及其他一些因素。最终,这通常涉及内核对程序内存空间进行一些直接且复杂的修改,以调用正确的响应。 - Z4-tier
哦,哇,我不知道这个。谢谢你告诉我! - AwesomeCronk

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