signal 信號

基於python學習筆記——多進程間通訊——Linux信號基礎的學習基礎,進一步學習Python標準庫中的signal模塊。python

儘管signal是python中的模塊,可是主要針對UNIX平臺(好比Linux,MAC OS),而Windows內核中因爲對信號機制的支持不充分,因此在Windows上的Python不能發揮信號系統的功能。函數

signal模塊負責python程序內部的信號處理;典型的操做包括信號處理函數、暫停並等待信號,以及定時發出SIGALRM等;post

1 signal基本信號名

import signal

signal.SIGHUP   # 鏈接掛斷;
signal.SIGILL   # 非法指令;
signal.SIGINT   # 終止進程(ctrl+c);
signal.SIGTSTP  # 暫停進程(ctrl+z);
signal.SIGKILL  # 殺死進程(此信號不能被捕獲或忽略);
signal.SIGQUIT  # 終端退出;
signal.SIGTERM  # 終止信號,軟件終止信號;
signal.SIGALRM  # 鬧鐘信號,由signal.alarm()發起;
signal.SIGCONT  # 繼續執行暫停進程;

二、 經常使用信號處理函數

2.1 設置發送SIGALRM信號的定時器

import signal
import time

signal.alarm(4)#4s後終止程序

while True:
    time.sleep(1)
    print("學習python中...")
學習python中...
學習python中...
學習python中...
鬧鐘

注意:在一個進程中,只能設置一個定時鬧鐘。若是設置第二個則會覆蓋第一個的時間,返回地一個的剩餘時間,第一個鬧鐘返回0。學習

使用signal.pasue阻塞函數:url

signal.pause() Wait until a signal arrives。讓進程進程暫停,以等待信號(什麼信號都可);也即阻塞進程進行,但不阻塞其餘信號,接收到信號後使進程中止spa

import signal
import time

print(signal.alarm(3)) # 0
time.sleep(1)
print(signal.alarm(4)) # 3

#阻塞等待信號的發生,如論什麼信號均可以
signal.pause()

while True:
    time.sleep(1)
    print("學習python中...")
0
2
鬧鐘

2.2 設置信號處理函數

 signal.signal(sig, handler) 操作系統

功能:按照handler制定的信號處理方案處理函數code

參數htm

sig:擬需處理的信號,處理信號只針對這一種信號起做用sig

hander:信號處理方案

    在信號基礎裏提到,進程能夠無視信號、可採起默認操做、還可自定義操做;當handler爲下列函數時,將有以下操做:

    SIG_IGN:信號被無視(ignore)或忽略

    SIG_DFL:進程採用默認(default)行爲處理

   function:handler爲一個函數名時,進程採用自定義函數處理

   不能處理,只能採用 也就是說hander的值有效值只有上面三種:不然報錯 TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object

示例代碼1、

import signal

#6s後終止程序
signal.alarm(6)

#遇到SIGINT ctrl+c時,忽略SIG_IGN
signal.signal(signal.SIGINT,signal.SIG_IGN)

signal.pause()
運行後6s 打印出: Alarm clock 

若是在運行中在鍵盤中輸入CTRL+C也無濟於事,此時輸出結果 ^C^C^C^C^C^C^C^C Alarm clock


緣由分析

(1)signal.signal(signal.SIGINT, signal.SIG_IGN) 表示遇到信號SIGINT  CTRL + C,時,忽略SIG_IGN該信號。 因此在程序運行中從鍵盤輸入ctrl+c(在終端上顯示 ^C )時無效。 (2)當signal.alarm(6)計時6秒後,直接在終端上輸出 「鬧鐘」 後退出。 (3)signal.pause()是爲了阻塞進程,等待信號。若是沒有這句話,能夠在程序中更變爲 while True: pass 效果同樣,若是沒有這段代碼,則沒有直接運行結束,終端上沒有任何輸出顯示。注意:這裏的signal.alarm()是在程序運行中,6秒後中止進程。

示例代碼二:

#進程中默認信號方式處理
import signal
#6s後終止程序
signal.alarm(6)
signal.signal(signal.SIGALRM,signal.SIG_DFL) #遇到鬧鐘信號按默認方式處理
signal.pause()#等信號。

示例代碼三:捕獲信號交給函數處理

有些原操做系統規定了的進程收到信號後的默認行爲,使用signal.signal()能夠經過綁定信號處理函數來修改進程收到信號後的行爲,實現個性化處理。

也即改變原默認行爲。

from signal import *
import time

def handler(signum,frame):
    if signum == SIGALRM:
        print('時間到了')
    elif signum == SIGINT:
        print("CTRL + C 無效")

alarm(5)
signal(SIGINT,handler)
signal(SIGALRM,handler)


while True:
    print('Waiting....')
    time.sleep(2)

這個代碼運行致使ctrl +c 沒法中斷運行

Waiting....
Waiting....
Waiting....
時間到了
Waiting....
^CCTRL + C 無效
Waiting....
^CCTRL + C 無效
Waiting....

說明:

(1)signal.signal() 經過綁定函數更變了信號的處理方式

(2)若是沒有改變alarm()信號的處理方式,signal.alarm()在運行5s後會將終止程序並輸出「鬧鐘」字樣

(3)從設備終端鍵盤輸入ctrl+c無效後,此時能夠輸入ctrl+\退出程序

(4)def handler(signum,frame)中frame,第一個參數是用來識別信號(signum),第二個信號是用來得到信號發生時,進程棧的情況(stack frame對象),這兩個參數都是由signal.signal()函數傳遞的。 參考 Frame objects

示例四:

CTRL+ Z信號

import signal

# Define signal handler function
def myHandler(signum, frame):
    print('I received: ', signum)

# register signal.SIGTSTP's handler
signal.signal(signal.SIGTSTP, myHandler)
signal.pause()
print('End of Signal Demo')
^ZI received:  20
I frame:  <frame at 0x7f0e1a1b29f8, file 'test6.py', line 10, code <module>>
End of Signal Demo
(base) [root@vm192-168-3-2 signal_study]# 

說明:

(1)signal.signal()函數來預設信號處理函數;

(2)當程序執行signal.pause()來讓進程暫停(被阻塞)以等待信號,此時,按下ctrl + z 向該進程發送SIGTSTP信號,當信號signal.SIGTSTP信號傳遞給該進程後,進程從被阻塞中恢復,並根據預設,執行SIGTSTP的信號處理函數myHandler()。

(3)myHandler()的兩個參數一個用來識別信號(signum),另外一個用來得到信號發生時,進程棧的情況(stack frame);這兩個參數都是有signal.signal()函數傳遞的。

(4)進程並不必定要使用signal.pause()暫停以等待信號,它也能夠在進行工做中接受信號,好比將上面的signal.pause()改成一個須要長時間工做的循環或死循環。

3 經常使用信號處理函數總結

 signal.signal(signalnum, handler)  設置信號處理的函數

 signal.alarm(time) 設置發送SIGALRM信號的定時器

 os.kill 這個不屬於signal模塊,但其可使用給某一進程發送信號

能夠捕獲的

signal.SIGHUP   # 鏈接掛斷;
signal.SIGILL   # 非法指令;
signal.SIGINT   # 終止進程(ctrl+c);
signal.SIGTSTP  # 暫停進程(ctrl+z);
signal.SIGQUIT  # 終端退出;
signal.SIGTERM  # 終止信號,軟件終止信號;
signal.SIGALRM  # 鬧鐘信號,由signal.alarm()發起;
signal.SIGCONT  # 繼續執行暫停進程;

不能夠被捕獲的:
signal.SIGKILL # 殺死進程(此信號不能被捕獲或忽略);
信號如何處理:只能 忽略/默認 或者自定義函數處理 signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object
相關文章
相關標籤/搜索