Linux程式設計之訊號處理
訊號是類Unix系統中的一種通知機制。在Linux下,我們可以通過kill -l命令來檢視有哪些訊號。Linux下有64個訊號,其中前32個訊號是經典訊號,後32個是用於驅動開發要用到的。
那麼訊號是如何產生的呢?主要有以下幾種方式可以產生訊號:
1.終端的特殊按鍵。比如說ctrl + d,ctrl + c等
2.kill 命令及函式。
3.硬體異常。如:非法訪問記憶體,除零操作。
4.某些軟條件已經發生。如:定時器alarm到時。
我們已經知道了訊號是如何產生的,那麼程序是如何對這些程序進行處理的呢?Linux系統對這些經典訊號提供了3種處理方式。
第一種是預設處理方式。在預設處理方式下,訊號有5種預設的動作,Term,Ign,Core,Stop,Cont,以下是它們的說明:
1.Term:終止當前程序
2.Ign:忽略該訊號
3.Core:終止當前程序並且產生Core檔案(用於除錯用的)
4.Stop:暫停當前程序
5.Cont:繼續執行先前暫停的程序
第二種是忽略該訊號。注意這裡的忽略和第一種情況下的Ign所在的層級是不一樣的。
我們先來看下訊號是如何響應的,在Linux的程序核心空間中,有兩個訊號集,一個是未決訊號集,只能被核心進行讀寫,使用者不能去修改它,但能去讀它。還有一個是訊號遮蔽字,這個使用者可以設定它。當有訊號產生時,未決訊號集裡剛產生的那個訊號位會被核心自動設定為1,表示該訊號產生了。接下來,如果訊號遮蔽字中對應的訊號遮蔽字位為0,說明該訊號沒有被遮蔽,可以去執行訊號的動作。若被遮蔽了,則該訊號不能被響應,直到遮蔽字位為0。當執行完該訊號的動作後,核心會將該訊號的未決訊號位設定為0。我們有幾個函式來對訊號集進行設定,sigemptyset(將訊號集全部置0),sigfillset
介紹了訊號集,我們來看下第三種處理方式。第三種是自定義訊號處理。我們可以通過sigaction函式來設定訊號的處理動作。該函式的第二個引數是一個名為struct sigaction 的結構體,其宣告如下:
以下是該函式的使用示例:struct sigaction { void (*sa_handler)(int); //訊號處理函式。早期版本的 void (*sa_sigaction)(int, siginfo_t *, void *);<span style="white-space:pre"> </span>//訊號處理函式,若使用這個就不能使用上一個,這個成員和上一個成員是互斥的,只能使用同一個 sigset_t sa_mask;<span style="white-space:pre"> </span>//臨時的訊號遮蔽字,通過該成員可以設定其它訊號的遮蔽位,執行完處理函式後,返回原有的訊號遮蔽字 int sa_flags;<span style="white-space:pre"> </span>//選擇使用哪個訊號處理函式,0表示使用早期版本的,SA_SIGINFO表示使用第二種 void (*sa_restorer)(void);<span style="white-space:pre"> </span>//保留的,沒有用 };
#include <stdio.h>
#include <signal.h>
void do_sig(int num)
{
//會列印該訊號的編號
printf("num = %d\n",num);
}
int main(void)
{
struct sigaction act;
//設定訊號處理函式
act.sa_handler = do_sig;
//將臨時訊號遮蔽字全設定為0
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
//設定SIGINT訊號使用自定義處理該訊號
sigaction(SIGINT,&act,NULL);
while(1)
{
printf("*********\n");
sleep(1);
}
return 0;
}