【问题标题】:How are signals and KeyboardInterrupt handled in Python?Python中如何处理信号和KeyboardInterrupt?
【发布时间】:2016-06-29 07:53:28
【问题描述】:

我有两个 Python 脚本 foo.pybar.pyfoo.py 将通过 os.system() 调用 bar.py

#foo.py
import os

print os.getpid()
os.system("python dir/bar.py")
#bar.py
import time

time.sleep(10)
print "over"

假设foo.py的pid是123,如果程序正常终止,就会打印出来

123
over

如果我在运行时输入kill 123,我会得到以下输出

123
Terminated
over

如果我在它运行时按 Ctrl-C,我会得到类似的东西

123
^CTraceback (most recent call last):
  File "dir/bar.py", line 4, in <module>
    time.sleep(10)
KeyboardInterrupt

但如果我在运行时输入kill -SIGINT 123,程序似乎会忽略信号并正常退出。

123
over

在我看来,
如果我输入kill 123,子进程不会受到影响。
如果我输入 Ctrl-C,两个进程都将被终止。
如果我在子进程运行时输入kill -SIGINT 123,信号将被忽略。

有人可以向我解释一下它是如何工作的吗?
Ctrl-Ckill -SIGINT 不应该是等效的吗?
如果我输入kill 123 是否保证子进程不会受到影响(如果它恰好正在运行)?

顺便说一句,我在 Ubuntu 14.04 上。谢谢!

【问题讨论】:

    标签: python multithreading process signals interrupt


    【解决方案1】:

    让我们依次考虑每种情况:

    如果我输入kill 123,子进程不会受到影响。

    是的,kill [pid] 就是这样工作的。它仅向您要终止的进程发送信号。如果你想将信号发送给一组进程,那么你必须使用代表process group的负数。

    如果我按 Ctrl-C,两个进程都会终止。

    我假设您的意思是“由 Ctrl-C 终止”。实际上,情况并非如此:只有孩子被终止。如果你在foo.py 的末尾添加一行print "I'm a little teapot",你会看到这一行被打印出来。发生的事情是孩子收到了信号。然后父级从os.system 继续。如果没有附加行,它看起来就像父级也受到 Ctrl-C 的影响,但事实并非如此,如附加行所示。

    您的 shell 确实将信号发送到与 tty 相关联的进程组,该进程组包括父级。 然而os.system 使用system 调用,该调用在进行调用的过程中阻塞了SIGINTSIGQUIT 信号。所以父母是免疫的。

    如果你不使用os.system那么你的进程会受到SIGINT的影响。试试这个代码foo.py:

    import os
    import subprocess
    
    print os.getpid()
    p = subprocess.Popen(["python", "dir/bar.py"])
    p.wait()
    print "I'm a little teapot"
    

    如果您在运行时按 Ctrl-C,您将获得两个回溯:一个来自父级,一个来自子级:

    $ python foo.py 
    29626
    ^CTraceback (most recent call last):
      File "dir/bar.py", line 4, in <module>
    Traceback (most recent call last):
      File "foo.py", line 8, in <module>
        time.sleep(10)
    KeyboardInterrupt    p.wait()
    
      File "/usr/lib/python2.7/subprocess.py", line 1389, in wait
        pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0)
      File "/usr/lib/python2.7/subprocess.py", line 476, in _eintr_retry_call
        return func(*args)
    KeyboardInterrupt
    

    如果我在子进程运行时输入kill -SIGINT 123,信号将被忽略。

    见上文。

    Ctrl-C 和kill -SIGINT 不应该是等价的吗?

    Ctrl-C 确实会向与您发出 Ctrl-C 的 tty 关联的前台进程组发送 SIGINT

    如果我输入kill 123,是否保证子进程不会受到影响(如果它恰好正在运行)?

    kill 123 本身只会将信号发送给pid 123 的进程。孩子不会受到影响。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-19
      • 1970-01-01
      • 2018-06-30
      • 2014-06-16
      • 2014-02-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多