简体   繁体   English

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

[英]delegate SIGINT signal to child process and then cleanup and terminate the parent

I have a main python(testmain.py) script that executes another python script(test.py) using subprocess.Popen command.我有一个主要的 python(testmain.py) 脚本,它使用 subprocess.Popen 命令执行另一个 python 脚本(test.py)。 When I press Ctrl-C , I want the child to exit with exit code 2 and then the parent to display that exit code and then terminate .当我按 Ctrl-C 时,我希望子进程以退出代码 2 退出,然后父进程显示该退出代码,然后终止。

I have signal handlers in both parent and child scripts.我在父脚本和子脚本中都有信号处理程序。

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)

I checked Delegate signal handling to a child process in python that is kind of similar to my question but in that case, the parent is continuing it's execution, which I don't want.在 python中检查了对子进程的委托信号处理,这有点类似于我的问题,但在这种情况下,父进程正在继续执行,这是我不想要的。

I want to: 1.exit test.py with exit(2) 2.print that exit code in testmain.py 3.exit test.py with exit(2)我想: 1.exit test.py with exit(2) 2.print that exit code in testmain.py 3.exit test.py with exit(2)

could someone please provide suggestions to do this?有人可以提供建议吗? Thanks.谢谢。

UPDATE : Handling the signal only in the child (test.py) and checking the return code in parent(testmain.py) will do what I want .更新:仅在子级 (test.py) 中处理信号并检查父级 (testmain.py) 中的返回代码将执行我想要的操作。

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

but I was wondering if there is a clean way to do this using signal handling.但我想知道是否有一种干净的方法可以使用信号处理来做到这一点。

Your child process shouldn't care what the parent does ie, if you want the child to exit with specific status on Ctrl+C then just do that:您的子进程不应该关心父进程的操作,即,如果您希望子进程以 Ctrl+C 上的特定状态退出,那么只需执行以下操作:

import sys

try:
    main()
except KeyboardInterrupt: # use default SIGINT handler
    sys.exit(2)

Or you could define the signal handler explicitly:或者您可以明确定义信号处理程序:

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()

There might be a difference in behavior if there are atexit handlers and/or multiple threads.如果有atexit处理程序和/或多个线程,则行为可能会有所不同。

Unrelated: depending on what your main() function does, there could be a significant delay before a signal is handled in Python.无关:根据您的main()函数的作用,在 Python 中处理信号之前可能会有明显的延迟。 Some blocking methods on Python 2 may ignore the signal completely: use Python 3 or apply a custom workaround for a specific case eg, using a timeout parameter for some calls. Python 2 上的一些阻塞方法可能会完全忽略信号:使用 Python 3 或针对特定情况应用自定义解决方法,例如,对某些调用使用超时参数。


You could handle SIGINT in a similar way in the parent:您可以在父级中以类似的方式处理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 doesn't restore signals for child processes eg, if you SIG_IGN the SIGINT signal in the parent, you could reset the necessary hanlders explicitly using preexec_fn parameter . Python 2 不会恢复子进程的信号,例如,如果您在父进程中SIG_IGN SIGINT信号,您可以使用preexec_fn参数显式重置必要的处理preexec_fn

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM