訊號是作業系統發給程序的一種資訊,程序會針對接收到的資訊做出相應的處理。
前面談到乙個概念,叫做訊號量,這裡所說的訊號量和我們今天談到的訊號,除了名字相似,事實上並沒有任何聯絡,是兩個完全不相關的概念,故不可混為一談。
訊號是如何產生的呢?先來說說熟悉的場景:
使用者輸入命令,在前台啟動乙個程序,然後按下ctri+c這個組合鍵,鍵盤產生乙個硬體中斷,終端驅動將ctrl+c解釋成乙個sigint訊號,寫入該程序的pcb中,這個過程也可以認為作業系統傳送了乙個sigint訊號給該程序。
這裡提到乙個概念,前台。乙個命令後面加&就可以放到後台執行,這樣shell不必等待程序執行結束就可以接收新的命令,啟動新程序。shell可以同時執行乙個前台程序和任意多個後台程序,只有前台程序才能接到組合鍵產生的訊號。
在前台程序執行的任意時刻都有可能接收到乙個sigint訊號,所以訊號相對於程序來說是非同步的。
與非同步相對的還有乙個概念叫做同步。
簡單的可以這麼理解,非同步就是臨時起意想要做的事情,同步就是兩者提前商量好到某一時刻幹某件事情。
那麼如何我們作業系統中到底有多少訊號呢?用kill -l
命令就可以檢視。
這些編號後面對應的就是每乙個訊號,從我們系統中的編寫習慣我們可以猜測這可能是乙個巨集,事實上也的確是這樣的,這些定義可以在signal.h中找到。
從中觀察34-64的訊號都很類似,這些都是實時訊號。又被認為是可靠訊號,訊號不會丟失,執行完處理動作後,不會恢復成預設處理動作。我們這裡主要討論非實時訊號。
剛才只說了一種訊號產生的方式,這裡我們來把訊號產生的方式都總結一下:
組合鍵:ctrl+c產生sigint訊號,ctrl+\產生sigquit訊號,ctrl+z產生sigtstp訊號。
硬體異常產生訊號,這些條件由硬體檢測到並通知核心,然後核心向當前程序傳送適當的訊號。如除零異常,就會傳送sigfpe訊號。
乙個程序呼叫kill(2)函式可以傳送訊號給另乙個程序。
軟體條件產生,如管道破裂。
訊號常見的處理方式有三種:
忽略就是我們收到了訊號,但是處理方式就是不做任何處理。那麼如果有程序在作業系統中出了異常,那是不是就無法終止了呢?並非如此,因為sigquit(3)和sigkill(9)號訊號是無法被忽略的。
預設處理就是原本在系統中內建的處理方式。
自定義處理我們在後面做出解釋。
在每個程序的pcb中分別都維護了這樣乙個資料結構,訊號產生時,核心在控制塊中設定該訊號的未決標誌,直到訊號遞達才清除該標誌。上圖sighup訊號未阻塞也未產生,當它遞達時執行預設處理動作。sigint訊號產生過,但正在被阻塞,所以暫時不能遞達。雖然它的處理動作是忽略,但在沒有解除阻塞之前不能忽略這個訊號,因為程序仍有集合改變處理動作之後再解除阻塞。如果某一訊號未產生過,但是block表中被修改為1,那麼一旦產生將被阻塞,再未解除阻塞之前,這個訊號將始終不能遞達。如果將這個訊號函式指標的指向改為自定義函式的位址,那麼它的處理動作就是自定義了。
posix允許系統遞達某一訊號一次或多次,linux下是這樣實現的:常規訊號在遞達之前產生多次只計一次,而實時訊號在遞達之前產生多次可以依次放在乙個佇列裡。
捕捉訊號:
如果訊號的處理動作是使用者自定義函式,在訊號遞達時候就呼叫這個函式,這稱之為捕捉訊號。由於訊號處理函式的**是在使用者空間實現的,所以執行對訊號的處理時會陷入核心,其流程圖大致如下:
從中我們可以看到,訊號在使用者和核心之間的切換可多達四次,每個用藍色圈出來的部分就是一次上下文切換。這就是訊號捕捉時在作業系統中呼叫的大致過程。
然後我們用一段**來演示訊號捕捉的過程。
模擬實現sleep函式
#include
#include
#include
void sig_alrm(int s)
unsigned
int mysleep(unsigned
int nsecs)
int main()
return
0;}
列印出訊號中的點陣圖:
#include
#include
#include
void printsigset(sigset_t *set)
else
}puts("");
}int main()
return
0;}
Linux下的訊號(二) 阻塞訊號
1,在此之前,必須先了解幾個概念 訊號遞達 delivery 實際執行訊號處理的動作。訊號未決 pending 訊號從產生到遞達之間的狀態。訊號阻塞 block 被阻塞的訊號產生時將保持在未決狀態,直到 程序解除對此訊號的阻塞,才 執行遞達的動作。注意 訊號阻塞和訊號忽略是不同的。只要訊號被阻塞就不...
Linux下的訊號以及訊號的處理
阻塞訊號 訊號捕捉 訊號處理 根據生活中的經驗,訊號就是向乙個事物傳遞某些資訊,在shell下啟動乙個前台程序,使用者輸入ctrl c,這個過程就相當於是再給核心傳遞乙個程序取消的訊號。那麼使用者按下ctrl c後,發生了什麼?在鍵盤上按下ctrl c等來產生訊號 include intkill p...
Linux下的SIGCHLD訊號
在之前我們為了避免出現殭屍程序我們採用了兩種方式 1 呼叫wait 函式使父程序去等待子程序。wait 是一種阻塞等待 2 呼叫waitpid 函式這也是父程序去等待子程序而waitpid 分為阻塞式等待和非阻塞式等待,輪詢的方式就是建立在非阻塞等待的基礎之上的 而sigchld訊號也可以避免出現殭...