2016-06-29 55 views
0

我有两个Python脚本foo.pybar.py,foo.py将通过os.system()调用bar.py在Python中如何处理信号和KeyboardInterrupt?

#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上的方式。谢谢!

回答

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的过程。小孩不会受到影响。