如何阻止SIGINT传递给python中的子进程?

shi*_*ino 13 python subprocess signals sigint intercept

我的python脚本用信号处理模块拦截SIGINT信号以防止过早退出,但是这个信号被传递给我用Popen打开的子进程.是否有一些方法可以防止将此信号传递给子进程,以便在用户按下ctrl-c时也不会过早退出?

Ben*_*Ben 15

启动signal.signal(signal.SIGINT, signal.SIG_IGN)子进程时会继承信号处理程序,因此如果使用信号模块忽略SIGINT(),那么您的子进程也会自动进行.

但有两个重要的警告:

  • 您必须生成子进程之前设置ignore处理程序
  • 自定义信号处理程序将重置为默认处理程序,因为子进程无法访问处理程序代码来运行它.

因此,如果您需要自定义SIGINT的处理而不是忽略它,您可能希望在生成子进程时暂时忽略SIGINT,然后(重新)设置自定义信号处理程序.

如果您正在尝试捕获SIGINT并设置一个标志,以便您可以在安全点退出而不是立即退出,请记住,当您到达安全点时,您的代码必须手动清理其后代,因为您的子进程和任何它启动的进程将忽略SIGINT.

  • @thejoshwolfe:为避免竞争条件,使用sigprocmask()来延迟信号,设置处理程序,fork,设置处理程序,然后再次使用sigprocmask重新启用信号.(如果在调用sigprocmask之间有任何信号到达,它们将在此时传递.) (2认同)
  • 请注意,SIGINT 可能仍会被子进程的子进程接收(例如,作为“python”中的子进程启动的“apt-get”可能会生成“dpkg”或“gpgv”)。在这种情况下,需要通过将“preexec_fn=os.setpgrp”传递给“subprocess.Popen”来创建一个新的进程组,并在父信号处理程序中处理所有内容(包括手动信号转发到子进程)。 (2认同)

jat*_*ism 2

您可以使用该tty模块重新分配 ctrl-c 的角色,这允许您操纵信号的分配。但请注意,除非您将它们恢复到修改之前的状态,否则它们将在 shell 的整个会话中持续存在,即使在程序退出后也是如此。

下面是一个简单的代码片段,可帮助您开始存储旧的 tty 设置,将 ctrl-c 重新分配给 ctrl-x,然后在退出时恢复以前的 tty 设置。

import sys
import tty

# Back up previous tty settings
stdin_fileno = sys.stdin.fileno()
old_ttyattr = tty.tcgetattr(stdin_fileno)

try:
    print 'Reassigning ctrl-c to ctrl-x'

    # Enter raw mode on local tty
    tty.setraw(stdin_fileno)
    raw_ta = tty.tcgetattr(stdin_fileno)
    raw_ta[tty.LFLAG] |= tty.ISIG
    raw_ta[tty.OFLAG] |= tty.OPOST | tty.ONLCR

    # ^X is the new ^C, set this to 0 to disable it entirely
    raw_ta[tty.CC][tty.VINTR] = '\x18'  

    # Set raw tty as active tty
    tty.tcsetattr(stdin_fileno, tty.TCSANOW, raw_ta)

    # Dummy program loop
    import time
    for _ in range(5):
        print 'doing stuff'
        time.sleep(1)

finally:
    print 'Resetting ctrl-c'
    # Restore previous tty no matter what
    tty.tcsetattr(stdin_fileno, tty.TCSANOW, old_ttyattr)
Run Code Online (Sandbox Code Playgroud)