Python 将SIGINT信号委托给子进程,然后清理并终止父进程

Python 将SIGINT信号委托给子进程,然后清理并终止父进程,python,linux,subprocess,signals,sigint,Python,Linux,Subprocess,Signals,Sigint,我有一个主python(testmain.py)脚本,它使用subprocess.Popen命令执行另一个python脚本(test.py)。当我按下Ctrl-C键时,我希望子对象以退出代码2退出,然后父对象显示该退出代码,然后终止 我在父脚本和子脚本中都有信号处理程序 testmain.py def signal_handler(signal, frame): print "outer signal handler" exit(2) signal.signal(signal.S

我有一个主python(testmain.py)脚本,它使用subprocess.Popen命令执行另一个python脚本(test.py)。当我按下Ctrl-C键时,我希望子对象以退出代码2退出,然后父对象显示该退出代码,然后终止

我在父脚本和子脚本中都有信号处理程序

testmain.py

def signal_handler(signal, frame):
    print "outer signal handler"
    exit(2)
signal.signal(signal.SIGINT, signal_handler) 

def execute()
proc=subprocess.Popen("python test.py",shell=True)
    streamdata=proc.communicate()[0]
    rc=proc.returncode
    print "return code:",rc

execute()
test.py

def signal_handler(signal, frame):
    print "exiting: inner function"
    exit(2)
signal.signal(signal.SIGINT, signal_handler)
我检查了一下,这有点像我的问题,但在这种情况下,家长正在继续执行,这是我不想要的

我想:1.exit test.py with exit(2)2.testmain.py中打印该退出代码3.exit test.py with exit(2)

有人能提供一些建议吗? 谢谢

更新:仅在子级(test.py)中处理信号,并在父级(testmain.py)中检查返回代码,这将满足我的需要

if rc==2:
   print "child was terminated"
   exit(2)

但我想知道是否有一种干净的方法可以使用信号处理来实现这一点。

您的子进程不应该关心父进程做什么,即,如果您希望子进程以Ctrl+C的特定状态退出,那么只需执行以下操作:

import sys

try:
    main()
except KeyboardInterrupt: # use default SIGINT handler
    sys.exit(2)
或者,您可以明确定义信号处理程序:

import os
import signal

def signal_handler(signal, frame):
    os.write(1, b"outer signal handler\n")
    os._exit(2)
signal.signal(signal.SIGINT, signal_handler)
main()
如果存在
atexit
处理程序和/或多个线程,行为可能会有所不同

无关:取决于
main()
函数的功能,在Python中处理信号之前可能会有明显的延迟。Python2上的某些阻塞方法可能会完全忽略信号:使用Python3或针对特定情况应用自定义解决方法,例如,对某些调用使用超时参数


您可以在父级中以类似的方式处理
SIGINT

for cmd in commands:
    process = Popen(cmd)
    try:
        process.wait()
    except KeyboardInterrupt:
        # child process may still be alive here
        for _ in range(5): # wait a while
           if process.poll() is not None:
               break # the process is dead
           time.sleep(.1)
        else: # no break, kill the process explicitly
           try:
               process.kill()    
           except OSError:
               pass
        sys.exit("Child exited with %d" % process.wait())

Python 2不会恢复子进程的信号,例如,如果父进程中的
SIG\u IGN
SIGINT信号,。

我认为在linux系统上会有问题,因为它设置的返回值与您的逻辑无关:(阅读最后一行)。顺便说一句:这似乎是一种不好的做事方式。@PadraicCunningham,我还没有通过全部代码。基本上,子脚本将执行一系列Linux命令。将有几个子脚本,每个子脚本执行不同的命令集。每个子脚本都将由主父脚本按顺序执行。若用户在两者之间按ctrl-C,那个么应该像我提到的那个样进行适当的处理。i、 e当前子进程应以退出代码2终止,父进程应显示此代码并停止。因此,您正在运行来自
testmain.py
的多个脚本,等待每个脚本完成,然后再关闭下一个?是@padraiccunninghamp可能的重复将很酷,请在此回答中提及有关信号如何工作的内容由子进程继承(或不继承)。@bennlich如果子进程未继承信号,则不需要在preexec_fn中恢复信号。虽然明确地提到它没有坏处