【问题标题】:What is the difference between Ctrl-C and SIGINT?Ctrl-C 和 SIGINT 有什么区别?
【发布时间】:2011-12-06 11:02:56
【问题描述】:

我一直在调试一个 Python 程序,该程序在收到 KeyboardInterrupt 异常后出现段错误。这通常通过在 shell 中按 Ctrl+C 来完成。为了测试特定的代码更改是否修复了这个错误,我有一个小的 shell 脚本,它在启动后随机向程序发送SIGINT。我遇到的问题是发送 Ctrl+C 似乎对程序的影响与发送信号 SIGINT 不同,因此不会导致错误出现,所以我很想知道有什么区别然后在两个动作之间。

该程序根本不会捕获任何键盘操作,它只是一个带有一些线程/进程的 python 程序。它不安装信号处理程序(尽管 Python 会),stty -a 提供 intr = ^C。我怀疑可能是 Ctrl+CSIGINT 发送到所有子进程/线程,而kill -INT 仅发送到主进程,但这是我的怀疑。

这是发送kill -INT的shell脚本。

wait
while :; do
    seconds="$(python -c 'import random; print random.random()*4')"
    ./mandos --debug --configdir=confdir \
             --statedir=statedir --no-restore --no-dbus &
    pid=$!
    { sleep $seconds; kill -INT $pid; } &
    fg %./mandos
    status=$?
    if [ $status -gt 1 ]; then
        echo "Failed exit $status after $seconds seconds"
        break
    fi
    wait
done

【问题讨论】:

  • 我不确定这会有多大的不同,但它可能的 ctrl+c 发送 SIGTERM 而不是 SIGINT。此外,在处理异常时,您是否正确清理了子进程/线程? python 处理线程的方式我不相信它会出现段错误,但它可能与子进程有关。
  • +C 可以配置,所以检查你的stty -a 设置,寻找intr = ^C,也许^C 也被设置为其他东西?
  • 代码中有多线程吗?
  • 刚刚看到您说您的 OP 中有线程。我会说这可能是你的问题。当脚本收到 SIGINT 时,线程没有正确终止。
  • 与发送信号 -INT 相比,如果您执行 ctrl + C,是否会影响线程?我说线程的原因是我使用多处理管理器,而python实现它的方式使用线程库。

标签: unix sigint keyboardinterrupt


【解决方案1】:

^C 向前台进程组中的所有进程发送SIGINT。要对kill 进行等效处理,您应该将信号发送到进程组(操作系统级别的概念):

kill -SIGINT -<pid>

或工作(shell级别的概念,管道以&amp;结尾):

kill -SIGINT %

【讨论】:

  • 这是我一直在寻找的,但由于未知原因,当我使用自动化脚本时,代码仍然没有段错误。我发现了导致python崩溃的错误——python库多处理是用线程实现的,如果不调用gobject.threads_init,它会导致gobject中的段错误。尽管如此,对我来说,最初的问题仍然是一个谜,为什么手动调用 ctrl+c 会触发错误,而自动脚本却没有。
  • 对不起,我的意思是迟钝,但是'%'在这个上下文中是什么意思?
  • @KevinCantwell:它指的是当前作业,即最后一个后台作业(要么在后台启动,要么在前台停止,因此在后台运行)。
  • @ninjalj 我是否正确假设它是将^C 转换为SIGINT 然后将后者发送到前台进程组中的进程的shell?或者 Python 解释器是否以任何方式参与了这个过程?
  • @balu:SIGINT 由线路规程处理,请参阅 termios(3) VINTR。另请参阅 stty(1) 以了解用于更改线路纪律设置的用户级命令。因此,shell 只需要正确配置线路规程,并使用 tcsetpgrp(3) 设置前台进程组。
【解决方案2】:

作为described here

Python 默认安装少量信号处理程序:SIGPIPE 被忽略(因此管道和套接字上的写入错误可以报告为 普通的 Python 异常)和 SIGINT 被翻译成 键盘中断异常。所有这些都可以被覆盖。

所以,发送 SIGINT 和 Ctrl + c 之间的行为应该相同。

但是,你必须小心KeyboardInterrupt,如果在你的代码的某个地方你有一个

try:
   ...
except:   # notice the lack of exception class
   pass

这将“吃掉”KeyboardInterrupt 异常。

【讨论】:

  • 感谢您的建议。找到了一条线,我认为这将修复一个不相关的错误。但即使注释掉了,段错误的主要问题仍然存在,更奇怪的是发送 kill -INT 不会触发它,但 ctrl + c 会。
  • 我喜欢这个答案,因为它明确 where 正是 SIGINT 和 KeyboardInterrupt 之间发生的翻译。至于您的警告:出于这个原因,我始终建议使用try: ... except Exception: ... 作为“正常”异常的全部内容,以免意外捕获KeyboardInterruptSystemExit 等不寻常的异常,比较link 1 和@ 987654323@.
猜你喜欢
  • 2011-06-29
  • 2021-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-05
  • 1970-01-01
相关资源
最近更新 更多