如何在Python中处理信号和KeyboardInterrupt?

时间:2016-06-29 07:53:28

标签: python multithreading process signals interrupt

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

#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 ,我将获得以下输出

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

如果我在运行时按 Ctrl - C ,我会得到像

这样的内容
kill -SIGINT 123

但如果我在123 over 运行时键入kill 123,程序似乎只会忽略该信号并正常退出。

kill -SIGINT 123

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

有人可以向我解释它是如何运作的吗? 是不是 Ctrl - C Name | Email | Phone number alis alis@123.com +989355555;+989366666;+9803777777 John john@yah.com +989122222 sara sara@yah.com +989113212;+989113312 应该是等价的?
如果我键入Name | Email | Phone number alis alis@123.com +989355555 alis alis@123.com +989366666 alis alis@123.com +9803777777 John john@yah.com +989122222 sara sara@yah.com +989113212 sara sara@yah.com +989113312 ,是否保证子流程不会受到影响(如果它正好在运行)?

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

1 个答案:

答案 0 :(得分: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会将SIGINT发送到与您发出Ctrl-C的tty相关联的前台进程组。

  

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

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