Linux信號機(jī)制詳細(xì)介紹
Linux信號機(jī)制詳細(xì)介紹
什么是Linux信號機(jī)制,Linux信號機(jī)制要講解起來沒那么簡單,本文只是給大家講解下Linux信號機(jī)制的基礎(chǔ)知識,讓你對Linux信號機(jī)制有一些了解,一起來學(xué)習(xí)下吧。
進(jìn)程基礎(chǔ)一文中已經(jīng)提到,Linux以進(jìn)程為單位來執(zhí)行程序。我們可以將計(jì)算機(jī)看作一個(gè)大樓,內(nèi)核(kernel)是大樓的管理員,進(jìn)程是大樓的房客。每個(gè)進(jìn)程擁有一個(gè)獨(dú)立的房間(屬于進(jìn)程的內(nèi)存空間),而每個(gè)房間都是不允許該進(jìn)程之外的人進(jìn)入。這樣,每個(gè)進(jìn)程都只專注于自己干的事情,而不考慮其他進(jìn)程,同時(shí)也不讓別的進(jìn)程看到自己的房間內(nèi)部。這對于每個(gè)進(jìn)程來說是一種保護(hù)機(jī)制。(想像一下幾百個(gè)進(jìn)程總是要干涉對方,那會有多么混亂,或者幾百個(gè)進(jìn)程相互偷窺……)
然而,在一些情況,我們需要打破封閉的房間,以便和進(jìn)程交流信息。比如說,內(nèi)核發(fā)現(xiàn)有一個(gè)進(jìn)程在砸墻(硬件錯(cuò)誤),需要讓進(jìn)程意識到這樣繼續(xù)下去會毀了整個(gè)大樓。再比如說,我們想讓多個(gè)進(jìn)程之間合作。這樣,我們就需要一定的通信方式。信號(signal)就是一種向進(jìn)程傳遞信息的方式。我們可以將信號想象成大樓的管理員往房間的信箱里塞小紙條。隨后進(jìn)程取出小紙條,會根據(jù)紙條上的內(nèi)容來采取一定的行動,比如燈壞了,提醒進(jìn)程使用手電。(當(dāng)然,也可以完全無視這張紙條,然而在失火這樣緊急的狀況下,無視信號不是個(gè)好的選擇)。相對于其他的進(jìn)程間通信方式(interprocess communication, 比如說pipe, shared memory)來說,信號所能傳遞的信息比較粗糙,只是一個(gè)整數(shù)。但正是由于傳遞的信息量少,信號也便于管理和使用。信號因此被經(jīng)常地用于系統(tǒng)管理相關(guān)的任務(wù),比如通知進(jìn)程終結(jié)、中止或者恢復(fù)等等。
給我一個(gè)信號
信號是由內(nèi)核(kernel)管理的。信號的產(chǎn)生方式多種多樣,它可以是內(nèi)核自身產(chǎn)生的,比如出現(xiàn)硬件錯(cuò)誤(比如出現(xiàn)分母為0的除法運(yùn)算,或者出現(xiàn)segmentation fault),內(nèi)核需要通知某一進(jìn)程;也可以是其它進(jìn)程產(chǎn)生的,發(fā)送給內(nèi)核,再由內(nèi)核傳遞給目標(biāo)進(jìn)程。內(nèi)核中針對每一個(gè)進(jìn)程都有一個(gè)表存儲相關(guān)信息(房間的信箱)。當(dāng)內(nèi)核需要將信號傳遞給某個(gè)進(jìn)程時(shí),就在該進(jìn)程相對應(yīng)的表中的適當(dāng)位置寫入信號(塞入紙條),這樣,就生成(generate)了信號。當(dāng)該進(jìn)程執(zhí)行系統(tǒng)調(diào)用時(shí),在系統(tǒng)調(diào)用完成后退出內(nèi)核時(shí),都會順便查看信箱里的信息。如果有信號,進(jìn)程會執(zhí)行對應(yīng)該信號的操作(signal action, 也叫做信號處理signal disposition),此時(shí)叫做執(zhí)行(deliver)信號。從信號的生成到信號的傳遞的時(shí)間,信號處于等待(pending)狀態(tài)(紙條還沒有被查看)。我們同樣可以設(shè)計(jì)程序,讓其生成的進(jìn)程阻塞(block)某些信號,也就是讓這些信號始終處于等待的狀態(tài),直到進(jìn)程取消阻塞(unblock)或者無視信號。
常見信號
信號所傳遞的每一個(gè)整數(shù)都被賦予了特殊的意義,并有一個(gè)信號名對應(yīng)該整數(shù)。常見的信號有SIGINT, SIGQUIT, SIGCONT, SIGTSTP, SIGALRM等。這些都是信號的名字。你可以通過
代碼如下:
$man 7 signal
來查閱更多的信號。
上面幾個(gè)信號中,
SIGINT 當(dāng)鍵盤按下CTRL+C從shell中發(fā)出信號,信號被傳遞給shell中前臺運(yùn)行的進(jìn)程,對應(yīng)該信號的默認(rèn)操作是中斷 (INTERRUPT) 該進(jìn)程。
SIGQUIT 當(dāng)鍵盤按下CTRL+\從shell中發(fā)出信號,信號被傳遞給shell中前臺運(yùn)行的進(jìn)程,對應(yīng)該信號的默認(rèn)操作是退出 (QUIT) 該進(jìn)程。
SIGTSTP 當(dāng)鍵盤按下CTRL+Z從shell中發(fā)出信號,信號被傳遞給shell中前臺運(yùn)行的進(jìn)程,對應(yīng)該信號的默認(rèn)操作是暫停 (STOP) 該進(jìn)程。
SIGCONT 用于通知暫停的進(jìn)程繼續(xù)。
SIGALRM 起到定時(shí)器的作用,通常是程序在一定的時(shí)間之后才生成該信號。
在shell中使用信號
下面我們實(shí)際應(yīng)用一下信號。我們在shell中運(yùn)行ping:
代碼如下:
$ping localhost
此時(shí)我們可以通過CTRL+Z來將SIGTSTP傳遞給該進(jìn)程。shell中顯示:
代碼如下:
[1]+ Stopped ping localhost
我們使用$ps來查詢ping進(jìn)程的PID (PID是ping進(jìn)程的房間號), 在我的機(jī)器中為27397
我們可以在shell中通過$kill命令來向某個(gè)進(jìn)程發(fā)出信號:
代碼如下:
$kill -SIGCONT 27397
來傳遞SIGCONT信號給ping進(jìn)程。
信號處理 (signal disposition)
在上面的例子中,所有的信號都采取了對應(yīng)信號的默認(rèn)操作。但這并不絕對。當(dāng)進(jìn)程決定執(zhí)行信號的時(shí)候,有下面幾種可能:
1) 無視(ignore)信號,信號被清除,進(jìn)程本身不采取任何特殊的操作
2) 默認(rèn)(default)操作。每個(gè)信號對應(yīng)有一定的默認(rèn)操作。比如上面SIGCONT用于繼續(xù)進(jìn)程。
3) 自定義操作。也叫做獲取 (catch) 信號。執(zhí)行進(jìn)程中預(yù)設(shè)的對應(yīng)于該信號的操作。
進(jìn)程會采取哪種操作,要根據(jù)該進(jìn)程的程序設(shè)計(jì)。特別是獲取信號的情況,程序往往會設(shè)置一些比較長而復(fù)雜的操作(通常將這些操作放到一個(gè)函數(shù)中)。
信號常常被用于系統(tǒng)管理,所以它的內(nèi)容相當(dāng)龐雜。深入了解信號,需要一定的Linux環(huán)境編程知識。
總結(jié)
信號機(jī)制; generate, deliver, pending, blocking
signal action/dispositon; ignore, default action, catch signal
$kill
上面就是Linux信號機(jī)制的相關(guān)介紹了,Linux信號機(jī)制遠(yuǎn)比想象中的復(fù)雜,短短幾個(gè)篇幅是很難講全的,如果你對Linux信號機(jī)制感興趣,可找相關(guān)書籍了解。