2014-02-18 85 views
1

所以我有這樣的代碼(從Python文檔部分採取):Python signal.signal是否阻止傳播?

import signal 

def handler(signum, frame): 
    print 'Signal handler called with signal', signum 

s = signal.signal(signal.SIGINT, handler) 

some_fancy_code() # this code is using subprocess.Popen() to call another script 

singal.signal(signal.SIGINT, s) 

我發現現在的問題是,如果我在我的程序做按Ctrl + C,它正確地進入該處理程序和打印。現在,我認爲在接收到Ctrl + C後,我的處理程序將禁止默認處理程序,例如我的子進程.Popen將不會獲得KeyboardInterrupt信號。但這種情況並非如此。

但是,當我們用'signal.SIG_IGN'替換'handler'時,這種傳播從不發生。修改後的代碼片段:

import signal 

s = signal.signal(signal.SIGINT, signal.SIG_IGN) 

some_fancy_code() # this code is using subprocess.Popen() to call another script 

singal.signal(signal.SIGINT, s) 

這是因爲SIG_IGN是用語言本身寫的某種'魔法'信號嗎?或者也許有辦法在我的處理程序中進行類似的壓制?

在閱讀了關於堆棧溢出的一些問題之後,我有點困惑。如果有人能夠向我澄清爲什麼這樣的行爲差異。

回答

2

這是信號指定的POSIX行爲:

A child created via fork(2) inherits a copy of its parent's signal dis‐ 
    positions. During an execve(2), the dispositions of handled signals 
    are reset to the default; the dispositions of ignored signals are left 
    unchanged. 

當您執行(叉/ execve的),你在第一種情況下的另一個劇本,SIGINT處理程序被重置爲在另一個腳本的默認處理程序(默認行爲是終止進程) - 當然,另一個腳本可以安裝自己的處理程序並改變這種行爲。

但是,在第二種情況下,您已將SIGINT配置爲忽略。此行爲將傳播到另一個腳本,如上面的定義中所示。同樣,另一個腳本可以通過安裝自己的處理程序來改變這種行爲。

所以這與Python直接無關。這是底層操作系統的POSIX信號處理實現的預期行爲。

PS。如果您想知道fork()和execve()是什麼,fork()會創建正在運行的進程(一個子進程)的副本,而execve()將用另一個進程替換當前進程。這是subprocess.Popen()用於運行'另一個腳本'的基本機制:首先製作當前進程的副本,然後將其替換爲目標進程。