作者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉載,也請保留這段聲明。謝謝!
在瞭解了Linux的訊號基礎之後,Python標準庫中的signal包就很容易學習和理解。signal包負責在Python程式內部處理訊號,典型的操作包括預設訊號處理函數,暫停並等待訊號,以及定時發出SIGALRM等。要注意,signal包主要是針對UNIX平台(比如Linux, MAC OS),而Windows核心中由於對訊號機制的支援不充分,所以在Windows上的Python不能發揮訊號系統的功能。
1. 定義訊號名
signal包定義了各個訊號名及其對應的整數,比如
import signalprint signal.SIGALRMprint signal.SIGCONT
Python所用的訊號名和Linux一致。你可以通過
$man 7 signal
查詢
2. 預設訊號處理函數
signal包的核心是使用signal.signal()函數來預設(register)訊號處理函數,如下所示:
singnal.signal(signalnum, handler)
signalnum為某個訊號,handler為該訊號的處理函數。我們在訊號基礎裡提到,進程可以無視訊號,可以採取預設操作,還可以自訂動作。當handler為signal.SIG_IGN時,訊號被無視(ignore)。當handler為singal.SIG_DFL,進程採取預設操作(default)。當handler為一個函數名時,進程採取函數中定義的操作。
import signal# Define signal handler functiondef myHandler(signum, frame): print('I received: ', signum)# register signal.SIGTSTP's handler signal.signal(signal.SIGTSTP, myHandler)signal.pause()
print('End of Signal Demo')
在主程式中,我們首先使用signal.signal()函數來預設訊號處理函數。然後我們執行signal.pause()來讓該進程暫停以等待訊號,以等待訊號。當訊號SIGUSR1被傳遞給該進程時,進程從暫停中恢複,並根據預設,執行SIGTSTP的訊號處理函數myHandler()。myHandler的兩個參數一個用來識別訊號(signum),另一個用來獲得訊號發生時,進程棧的狀況(stack frame)。這兩個參數都是由signal.singnal()函數來傳遞的。
上面的程式可以儲存在一個檔案中(比如test.py)。我們使用如下方法運行:
$python test.py
以便讓進程運行。當程式運行到signal.pause()的時候,進程暫停並等待訊號。此時,通過按下CTRL+Z向該進程發送SIGTSTP訊號。我們可以看到,進程執行了myHandle()函數, 隨後返回主程式,繼續執行。(當然,也可以用$ps查詢process ID, 再使用$kill來發出訊號。)
(進程並不一定要使用signal.pause()暫停以等待訊號,它也可以在進行工作中接受訊號,比如將上面的signal.pause()改為一個需要長時間工作的迴圈。)
我們可以根據自己的需要更改myHandler()中的操作,以針對不同的訊號實現個人化的處理。
3. 定時發出SIGALRM訊號
一個有用的函數是signal.alarm(),它被用於在一定時間之後,向進程自身發送SIGALRM訊號:
import signal# Define signal handler functiondef myHandler(signum, frame): print("Now, it's the time") exit()# register signal.SIGALRM's handler signal.signal(signal.SIGALRM, myHandler)signal.alarm(5)while True: print('not yet')
我們這裡用了一個無限迴圈以便讓進程持續運行。在signal.alarm()執行5秒之後,進程將向自己發出SIGALRM訊號,隨後,訊號處理函數myHandler開始執行。
4. 發送訊號
signal包的核心是設定訊號處理函數。除了signal.alarm()向自身發送訊號之外,並沒有其他發送訊號的功能。但在os包中,有類似於linux的kill命令的函數,分別為
os.kill(pid, sid)
os.killpg(pgid, sid)
分別向進程和進程組(見Linux進程關係)發送訊號。sid為訊號所對應的整數或者singal.SIG*。
實際上signal, pause,kill和alarm都是Linux應用編程中常見的C庫函數,在這裡,我們只不過是用Python語言來實現了一下。實際上,Python 的解譯器是使用C語言來編寫的,所以有此相似性也並不意外。此外,在Python 3.4中,signal包被增強,訊號阻塞等功能被加入到該包中。我們暫時不深入到該包中。
總結:
signal.SIG*
signal.signal()
signal.pause()
signal.alarm()