我們在講進程的多種狀態時提到過,一個進程的退出有三種情況:正常退出,結果出錯退出(代碼也執行完了),異常終止退出(代碼未執行完),其中最后一種退出相當于進程在運行時,突然收到某個”消息“,使自己不得不終止運行,這種”消息“就是信號。本文我們主要講到什么是信號、產生的方式以及應用情景等。
一、什么是信號
在生活中,我們也會有很多信號,比如下課鈴響了我們知道下課了,綠燈來了我們知道該走了,也就是說,它們在向我們發出某種消息,使得我們去做一些事情,在操作系統中也類似,信號就是其他進程,向目標進程發送異步事件的一種方式。所謂異步,就是指目標進程自己也不知道這個信號什么時候來,突然、隨時的情況。
二、關于信號你需要知道的一些知識
1.我們如何識別信號呢?
識別信號是內置的。進程認識信號,是程序內置的特性。就相當于我們從小就被告知紅燈停綠燈行
2.信號產生后該如何處理知道嗎?如果沒有產生,信號又該如何處理知道嗎?
全都知道!因為信號處理的方法,在信號產生之前,就已經準備好了,就像我們從來沒遇見紅綠燈時,家長告訴我們如果遇到了應該這樣做。
3.信號來的時候,我需要立即處理嗎?
不一定,因為此時我正在做的事情優先級比較高,可能在某個合適的時候再進行處理。但進程需要把信號記錄下來。
4.如何處理信號?
a.默認行為(我們早就被告知正常應如何做)
b.忽略信號(并不是不處理,而是遇見信號后對其完成忽略操作,比如鬧鐘響了我把它關閉并設置成一小時后再響)
c.自定義行為 (我雖然是被告知如果遇見信號該如何做,但是我也可以不聽它的,按照自己的想法去做)
三、信號的產生方式
1. 鍵盤產生
我們知道,在Linux中想執行一個程序只需要輸入 ./name即可,這種方式我們稱前臺進程。對應的還有后臺進程(程序在后臺運行)語法為 ./name &。二者的區別是:前臺進程相當于把命令行解釋占用了,當進程運行時,我們無法進行輸入操作來完成某些命令,而后臺進程運行時,我們依舊可以進行命令行解釋(后臺進程也可以把內容打印在顯示器上)。我們之前提到的熱鍵Ctrl+C,其實是終止前臺進程的命令。至于如何終止后臺命令,a.我們可以再打開一個終端然后找到進程的pid進行kill操作 b.我們在使用./name &時,它會顯示一個下標和pid,我們只需要使用命令fg 下標(比如fg 1)即可把對應下標的進程放置前臺運行,然后再ctrl+c。我們輸入ctrl+c時,實質上是把某種信號給了前臺進程,使其終止。至于信號的捕捉,我們有系統調用
其就是把指定的信號(參數1)按照自定義的方式(參數2)去捕捉
其中我們第二個參數要傳函數的地址。函數的類型是void且參數是int(輸出型參數,會用信號的序號賦值)
查看所有的信號我們用命令:kill -l
其中,我們的ctrl+c傳給進程的就是2號信號(每一個信號名稱都是宏)與此功能類似的是3號信號,默認也是終止,熱鍵是ctrl+\ (我們只重點講1-31號)
在1-31號中,大部分都是和進程終止相關的信號,且基本都能被signal捕捉,但有一個信號是絕對不可能被捕捉的——9號,它也是殺掉進程的信號,我們常與kill命令結合終止命令。
關于signal有兩點補充:
(1)對于同一個信號,signal捕捉一次即可,不必放在循環中
? (2)? ?若沒有產生某種信號,signal中的handler一般不會被調用
言歸正傳,我們從鍵盤輸入是如何轉化成信號的?過程是,我們從鍵盤輸入的內容,先是交給了OS,然后OS再把我們的內容轉化為對應的信號傳遞給進程,但我們說過,進程并不是收到信號立馬就處理,有時候也需要記錄信號,那么進程記錄信號的方式是:在PCB中創建一個位圖(記錄1-31號,比特位的位置為信號的編號,比特位是否為1表示是否收到對應的信號,所以,發送信號的本質是寫入信號,即OS修改該進程PCB中的位圖。
那么OS怎么知道鍵盤上有數據了?
我們引進一個名詞——硬件中斷,根據馮諾依曼體系,我們的鍵盤屬于輸入設備,按道理來講OS會不斷地檢測鍵盤是否有內容輸入,但現在不用了,當鍵盤輸入完畢的時候,會向OS發出硬件中斷的信號,OS收到信號再來獲取數據。
2.指令中斷
關于中斷進程的指令,我們剛才也提到過,也就是kill
kill -num pid
3.系統調用
沒錯,kill也是系統調用,返回值小于0表示發送信號失敗
除此之外,還有一個系統調用——raise
它的特點是,把你要傳的信號序號進行傳參,然后誰調用這個系統調用就把這個信號傳給誰。
還有不傳參版的——abort
4.軟件條件
在OS中因某些軟件還沒準備好,或不具備某種條件而產生的信號方式就是軟件條件。比如我們之前提到的管道,當管道的讀端關閉寫端仍要寫入,操作系統就會發送信號(13號)殺死這個進程,這就是軟件條件不具備。除此之外還有一個例子——鬧鐘
可以設定我們的進程在多長時間后自動終止。即到指定時間后由OS向進程發送指定信號(14)
至于其返回值,當alarm傳參為0時,表示取消鬧鐘,此時返回值就是上一個鬧鐘的剩余時間。
5.異常?
進程出現異常的情形大多數是因為野指針、除0操作,當進程出現異常了,OS會向進程發送8//11信號來殺死進程。
四、core與term
我們查信號手冊時,發現有的進程是core有的是term,他們有什么區別呢?
term類型是正常終止進程,而core類型比它多做了一件事——核心轉儲
當進程收到信號要終止時,會在當前目錄下形成文件->pid.core,當進程崩潰時,會把進程在內存的信息保存起來,方便后續調試。但云服務器一般是關閉core的這個功能的。