2016-06-29 60 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的過程。小孩不會受到影響。