【问题标题】:delegate SIGINT signal to child process and then cleanup and terminate the parent将 SIGINT 信号委托给子进程,然后清理并终止父进程
【发布时间】:2015-12-05 21:41:18
【问题描述】:

我有一个主 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)

我检查了Delegate signal handling to a child process in python,这有点类似于我的问题,但在这种情况下,父母会继续执行它,这是我不想要的。

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

有人可以提供建议吗? 谢谢。

更新:仅在子级(test.py)中处理信号并检查父级(testmain.py)中的返回码将做我想要的。

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

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

【问题讨论】:

  • 我认为您在 linux 系统上会遇到问题,因为无论您的逻辑如何,它都会设置返回:docs.python.org/2/library/…(阅读最后一行)。附带说明:这似乎是做某事的坏方法。
  • @PadraicCunningham ,我还没有通过整个代码。基本上,子脚本将执行一堆 Linux 命令。并且会有几个子脚本,每个脚本执行不同的命令集。每个子脚本将由主父脚本依次执行。如果用户在两者之间按下 ctrl-C,则应如我所提到的那样对其进行适当处理。即当前子进程应以退出代码 2 终止,父进程应显示此代码并停止。
  • 所以您正在运行来自testmain.py 的多个脚本,等待每个脚本完成后再执行下一个?
  • 是的@PadraicCunningham

标签: python linux subprocess signals sigint


【解决方案1】:

您的子进程不应该关心父进程的操作,即,如果您希望子进程在 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 中处理信号之前可能会有很大的延迟。 Python 2 上的一些阻塞方法可能会完全忽略该信号:使用 Python 3 或针对特定情况应用自定义解决方法,例如,对某些调用使用超时参数。


您可以在父级中以类似的方式处理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_IGNSIGINT 信号,you could reset the necessary hanlders explicitly using preexec_fn parameter

【讨论】:

  • 在这个答案中提到一些关于信号如何被子进程继承(或不继承)的事情会很酷。
  • @bennlich 如果子进程没有继承信号,则无需恢复 preexec_fn 中的信号。虽然明确提及它并没有什么坏处
猜你喜欢
  • 1970-01-01
  • 2021-12-04
  • 2016-03-22
  • 1970-01-01
  • 2010-09-23
  • 2017-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多