Python Signal

信號Signal

信號Signal的全稱為軟中斷信號商虐,是用來通知進程發(fā)生了異步事件,是在軟件層次上對中斷機制的一種模擬进胯。原理上一個進程收到一個信號與CPU收到一個中斷請求可以說是類似的。

信號是進程間通信機制中唯一的異步通信機制,一個進程不必通過任何操作來等待信號的到達逆皮。事實上進程也不知道信號到底什么時候到達,進程之間可以相互通過系統(tǒng)調用kill發(fā)送軟中斷信號参袱。內核也可以因為內部事件而給進程發(fā)送信號电谣,通知進程發(fā)生了某個事件。信號機制除了基本通知功能外抹蚀,還可以傳遞附加信息剿牺。

信號是Linux系統(tǒng)編程中非常重要的概念,信號機制是進程間傳遞消息的一種機制环壤,是異步進程中通信的一種方式晒来。比如終端用戶輸出Ctrl+c來終端程序時會通過信號機制停止程序的執(zhí)行。

信號的作用是通知進程發(fā)生了異步事件郑现,進程之間可以調用系統(tǒng)傳遞信號湃崩,內核本身也可以發(fā)送信號給進程荧降,告知該進程發(fā)生了某個事件。在應用層可以將消息傳遞給內核監(jiān)控攒读,當消息處理完畢后誊抛,內核將消息反饋給應用層,這樣操作不會出現(xiàn)阻塞等待整陌,保持信號處理的持續(xù)性拗窃。

相對于共享內存,信號更加偏向于系統(tǒng)層面泌辫,Linux系統(tǒng)也是通過信號管理進程的随夸,而且系統(tǒng)規(guī)定了某些進程接收到某些信號后的行為 。

一個進程一旦接收到信號就會打斷原來的程序執(zhí)行流程來處理信號震放。不過需要注意要的是宾毒,信號只是用來通知某進程發(fā)生了什么事件,并不會給該進程傳遞任何數(shù)據(jù)殿遂。

信號生命周期

對于一個完整的信號生命周期诈铛,從信號發(fā)送到相應的處理函數(shù)執(zhí)行完畢來說,墨礁,可以以分為三個階段:信號誕生幢竹、信號在進程中注冊、信號的執(zhí)行和注銷恩静。

  • 信號誕生

信號事件的發(fā)生有兩個來源分別是硬件來源和軟件來源焕毫,最常用發(fā)送信號的系統(tǒng)函數(shù)是killraise驶乾、alarm邑飒、settimersigqueue级乐,軟件來源還包含一些非法運算等操作疙咸。

  • 信號在目標進程中注冊

在進程表的表項中有一個軟中斷信號域,該域中每一位對應一個信號风科。內核給一個進程發(fā)送軟中斷信號的方法撒轮,是在進程所在的進程表項的信號域中設置對應于該信號的位。如果信號發(fā)送給一個正在休眠的進程丐重,此時如果進程睡眠在可被中斷的優(yōu)先級上則會喚醒進程腔召,否則僅設置進程表中信號域相應的位而不喚醒進程。如果發(fā)送給一個處于正在運行狀態(tài)的進程則只置相應的域即可扮惦。

  • 信號的執(zhí)行和注銷

內核處理一個進程收到的軟中斷信號是在該進程的上下問臀蛛,因此進程必須處于運行狀態(tài)。當其被信號喚醒或正常調度重新獲得CPU時,再從內核空間返回到用過戶空間時會檢測是否有信號等待處理浊仆。如果存在未決信號等待處理且該信號沒有被進程阻塞客峭,則在運行相應的信號處理函數(shù)前,進程會將信號在未決信號鏈中占有的結構卸掉抡柿。

信號處理

接收信號的進程對不同的信號有三種處理方式:指定處理函數(shù)舔琅、忽略、根據(jù)系統(tǒng)默認值處理(大部分信號的默認處理時終止進程)洲劣。

  • 忽略信號

大多數(shù)信號可以使用忽略信號這種方式來處理备蚓,但有兩種信號不能被忽略,分別是SIGKILLSIGSTOP囱稽。因為它們向內核和超級 與用戶提供了進程終止和停止的可靠方法郊尝。如果忽略了,那么進程就 會變的沒人能夠管理战惊,顯然這是內核設計者不希望看到的場景流昏。

  • 捕捉(指定處理函數(shù))

需要告知內核用戶希望如何處理某一種信號,簡單來說就是寫一個信號處理函數(shù)吞获,然后將這個函數(shù)告訴內核况凉。當該信號產生時,由內核來調度用戶自定義的函數(shù)各拷,以此實現(xiàn)某種信號的處理刁绒。

  • 系統(tǒng)默認動作

對于每個信號來說,系統(tǒng)都對應有默認的處理動作撤逢,當發(fā)生了該信號系統(tǒng)會自動執(zhí)行膛锭。不過對系統(tǒng)來說粮坞,大部分的處理方式都比較粗暴蚊荣,也就是直接殺死該進程。

信號表示

每個信號都有一個名字和編號莫杈,這些名字都是以SIG開頭互例,信號定義在signal.h頭文件中,其中信號名都定義為正整數(shù)筝闹,具體的信號名稱可以通過kill -l來查看媳叨。信號是從1開始編號,不存在0號信號关顷,因為kill對信號0有特殊的應用糊秆。

對于常用的kill命令其實是一個發(fā)送信號的工具,比如使用kill -9 PID來殺死指定PID的進程议双,其中-9表示信號列表中9號即SIGKILL信號痘番,表示殺死該進程的信號。

$ kill -l
 1) SIGHUP   2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP
 6) SIGABRT  7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG  24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF 28) SIGWINCH    29) SIGIO   30) SIGPWR
31) SIGSYS  34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX    

信號分類

  • POSIX標準規(guī)則信號regular signal 1-31
  • 實時信號real-time signal 32-63

由于不同系統(tǒng)中同一個數(shù)值對應的信號類型不同,所以最好使用信號名稱汞舱。另外伍纫,信號的數(shù)值越小,優(yōu)先級越高昂芜。

信號通信

  • 被動式
    內核檢測到一個系統(tǒng)事件莹规,比如子進程退出時會向父進程發(fā)送SIGCHLD信號,當鍵盤按下Ctrl+C時會發(fā)送SIGINT信號等泌神。
  • 主動式
    比如通過系統(tǒng)調用kill向指定進程發(fā)送信號

常見信號

  • SIGINT 表示鍵盤按下Ctrl+c鍵時會發(fā)送給前臺的每一個進程良漱。
  • SIGQUIT 表示鍵盤按下Ctrl+\
  • SIGSTP 表示鍵盤按下Ctrl+z
  • SIGKILL 表示結束某個進程,不能被忽略處理欢际。
  • SIGALRM 表示時鐘信號债热,常用作定時器。
  • SIGSTOP表示暫停某個進程幼苛,且不能被忽略處理窒篱。
  • SIGCHLD表示子進程發(fā)送給父進程信號

可以在中斷輸入kill -l命令查看系統(tǒng)支持的所有信號列表

kill -l [信號聲明]
kill [-s 信號聲明 | -n 信號編號 | -信號聲明] 進程號 | 任務聲明...
  • 在信號列表中,34號之后的信號尚未定義舶沿。
  • 進程結束信號可使用SIGKILLSIGTERM
    • 對于SIGKILL結束信號時墙杯,進程是不能忽略的,該信號意味著不管進程正在做什么都必須立即停止括荡。
    • 對于SIGTERM結束信號是比較友好的高镐,進程能捕捉到這個信號,會根據(jù)用戶的需要來關閉程序畸冲。在關閉程序之前嫉髓,可以結束打開的記錄文件和完成正在做的任務。在某些情況下邑闲,假如進程正在進行作業(yè)而且不能中斷算行,那么進程可以忽略這個SIGTERM信號。

Python信號模塊signal

盡管signal是Python中的模塊苫耸,但主要針對UNIX平臺州邢,而Windows內核中由于對信號機制支持不充分,所以在Windows上的Python不能發(fā)會信號系統(tǒng)的功能褪子。

Python的signal模塊負責程序內部的信號處理量淌,典型的操作包括信號處理函數(shù)、暫停并等待信號嫌褪,定時發(fā)出SIGALRM等呀枢。

加載模塊

import signal

信號名稱

# 連接掛斷
signal.SIGUP
# 非法指令
signal.SIGILL
# 終止進程
signal.SIGINT

SIGINT信號編號為2,當按下鍵盤CTRL+c組合鍵時進程會收到此信號笼痛,用于終止進程裙秋。

# 暫停進程CTRL+z
signal.SIGSTP
# 殺死進程,此信號不能被捕獲或忽略。
signal.SIGKILL

SIGKILL信號用于強制殺死進程残吩,此信號進程無法忽視财忽,直接在系統(tǒng)層面將進程殺死,所以在Python中它是不能監(jiān)聽的泣侮。

# 終端退出
signal.SIGQUIT
# 終止信號即彪,軟件終止信號。
signal.SIGTERM

當終端用戶輸入kill sigerm pid時對應PID的進程會接收到此信號活尊,此信號進程是可以捕獲并指定函數(shù)處理隶校。比如做一下程序清理等工作,當然也是可以忽視此信號的蛹锰。

# 鬧鐘信號深胳,由signal.alarm()發(fā)起。
signal.SIGALRM
# 繼續(xù)執(zhí)行暫停進程
signal.SIGCONT

信號處理函數(shù)

設置發(fā)送SIGALRM信號的定時器

signal.alarm(time)
  • 功能:在time秒后向進程自身發(fā)送SIGALRM信號
  • 參數(shù):time為時間參數(shù)铜犬,單位為秒舞终。

例如:設置時鐘

$ vim sigalrm.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import signal, time

# 3秒后終止程序
signal.alarm(3)

while True:
    time.sleep(1)
    print("working")
$ python sigalrm.py
working
working
鬧鐘

一個進程中只能設置一個時鐘,如果設置第二個則會覆蓋第一個的時間癣猾,并返回第一個的剩余時間敛劝,同時第一個鬧鐘返回為0。

例如:當在一個程序中出現(xiàn)兩個signal.alarm()函數(shù)時

$ vim sigalrm.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import signal, time

# 3秒后終止程序
print(signal.alarm(3)) # output:0
time.sleep(1)
print(signal.alarm(3)) # output:2

while True:
    time.sleep(1)
    print("working")
$ python sigalrm.py
0
2
working
working
鬧鐘

使用signal.pause阻塞函數(shù)纷宇,讓進程暫停以等待信號夸盟,也就時阻塞進程執(zhí)行,簡單來說當接收到信號后使進程停止像捶。

例如:

$ vim sigalrm.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import signal, time

# 3秒后終止程序
print(signal.alarm(3)) # output:0
time.sleep(1)
print(signal.alarm(3)) # output:2

# 阻塞等待信號的發(fā)生上陕,無論什么信號都可以。
signal.pause()

while True:
    time.sleep(1)
    print("working")
$ python sigalrm.py
0
2
鬧鐘

使程序進入休眠

signal.pause()
  • 作用:使程序進入休眠直到程序接收到某個信號量

獲取當前程序注冊signalnum信號量的處理函數(shù)

signal.getsignal(signalnum)
  • 作用:獲取當前程序注冊signalnum信號量的處理函數(shù)
  • 返回值:可能使Python可調用對象如signal.SIG_DFL拓春、signal.SIG_IGN释簿、None

設置信號處理函數(shù)

signal.signal(sig, handler)
  • 功能:按照handler處理器制定的信號處理方案處理函數(shù)
  • 參數(shù):
    • sig擬需處理的信號 痘儡,處理信號只針對這一種信號其作用辕万。
    • handler信號處理方案,進程可以無視信號采取默認操作也可自定義操作沉删。

handler為下列函數(shù)時將有如下操作

  • SIG_IGN信號被無視ignore或忽略
  • SIG_DFL進程采用默認default行為處理
  • function處理器handler作為函數(shù)名稱時,進程采用自定義函數(shù)處理醉途。
  • SIGSTOP SIGKILL不能處理只能采用

例如:

$ vim signal.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import signal, time

# 3秒后終止程序
signal.alarm(3)
# 當遇到SIGINT即CTRL+C時忽略SIG_IGN
signal.signal(signal.SIGINT, signal.SIG_IGN)
# 阻塞等待信號的發(fā)生矾瑰,無論什么信號都可以。
signal.pause()
$ python signal.py
鬧鐘

信號攔截

為什么需要設置信號攔截呢隘擎?如果使用多線程或多協(xié)程殴穴,為了防止主線程結束而子線程和子協(xié)程還在運行,此時就需要使用signal模塊,使用signal模塊可以綁定一個處理函數(shù)采幌,當接收步到信號的時候不會立即結束程序劲够。

在Python中攔截信號通常有兩種方式

  • 第一種是發(fā)出kill信號
# SIGTERM 表示關閉程序信號
signal.signal(signal.SIGTERM, self._term_handler)
  • 第二種是發(fā)出CTRL+C信號
# SIGINT表示CTRL+C信號
signal.signal(signal.SIGINT, self._term_handler)

在多線程多協(xié)程的程序設計時,一般多線程或的多協(xié)程程序在設計時應該設計一個程序終止標記休傍,當收到終止信號的時候征绎,讓終止標記狀態(tài)由False修改為True,此時運行的程序只有終止標記在False狀態(tài)下時才能夠以運行磨取。如果由需要休眠的協(xié)程人柿,還應給協(xié)程增加一個休眠標記,當程序休眠的時候休眠標記設置為True忙厌,當收到終止信號的時候凫岖,不僅僅要把終止標記設置為True,還要將休眠中的協(xié)程結束掉逢净。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末哥放,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子爹土,更是在濱河造成了極大的恐慌婶芭,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件着饥,死亡現(xiàn)場離奇詭異犀农,居然都是意外死亡,警方通過查閱死者的電腦和手機宰掉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門呵哨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人轨奄,你說我怎么就攤上這事孟害。” “怎么了挪拟?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵挨务,是天一觀的道長。 經常有香客問我玉组,道長谎柄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任惯雳,我火速辦了婚禮朝巫,結果婚禮上,老公的妹妹穿的比我還像新娘石景。我一直安慰自己劈猿,他們只是感情好拙吉,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著揪荣,像睡著了一般筷黔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上仗颈,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天佛舱,我揣著相機與錄音,去河邊找鬼揽乱。 笑死名眉,一個胖子當著我的面吹牛,可吹牛的內容都是我干的凰棉。 我是一名探鬼主播损拢,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼撒犀!你這毒婦竟也來了福压?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤或舞,失蹤者是張志新(化名)和其女友劉穎荆姆,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體映凳,經...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡胆筒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了诈豌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仆救。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖矫渔,靈堂內的尸體忽然破棺而出彤蔽,到底是詐尸還是另有隱情,我是刑警寧澤庙洼,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布顿痪,位于F島的核電站,受9級特大地震影響油够,放射性物質發(fā)生泄漏蚁袭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一叠聋、第九天 我趴在偏房一處隱蔽的房頂上張望撕阎。 院中可真熱鬧,春花似錦碌补、人聲如沸虏束。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镇匀。三九已至,卻和暖如春袜啃,著一層夾襖步出監(jiān)牢的瞬間汗侵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工群发, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留晰韵,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓熟妓,卻偏偏與公主長得像雪猪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子起愈,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內容

  • 一只恨、什么是信號 軟中斷信號(signal,又簡稱為信號)用來通知進程發(fā)生了異步事件抬虽。進程之間可以互相通過系統(tǒng)調用 ...
    河碼匠閱讀 1,802評論 0 1
  • 又來到了一個老生常談的問題官觅,應用層軟件開發(fā)的程序員要不要了解和深入學習操作系統(tǒng)呢? 今天就這個問題開始阐污,來談談操...
    tangsl閱讀 4,088評論 0 23
  • 文/tangsl(簡書作者) 原文鏈接:http://www.reibang.com/p/2b993a4b913e...
    西葫蘆炒胖子閱讀 3,744評論 0 5
  • 對于 Linux來說休涤,實際信號是軟中斷,許多重要的程序都需要處理信號笛辟。信號功氨,為 Linux 提供了一種處理異步事件...
    故事狗閱讀 84,661評論 2 62
  • 都挺好,就是隘膘,這也有點不行疑故,那兒也不太好。 今天還行嘛弯菊? 挺好纵势。 哦哦。那你看起來有點兒累管钳。 是吧钦铁,哎~ 不是說挺...
    白月之地閱讀 246評論 0 0