在Linux中信號也稱為軟中斷,進程在收到信號之後在對信號進行處理,可以說就是一個中斷的過程。本文就來為大家簡單地解析一下Linux信號機制。
1、安裝信號處理函數
在系統編程的層面上與信號的處理關系最直接相關的函數有兩個,他們用來安裝信號處理函數:
sighandler_t signal(int signum, sighandler_t handler);
int sigaction(int signum, const struct sigaction *act,,struct sigaction *oldact);
第一個函數signal比較簡單,sighandler_t 是一個別名,其原型是 typedef void (*sighandler_t)(int),他是一個函數指針,接受一個類型為int的參數(信號的編號),返回void。例如要對SIGUSR1信號進行處理:
void handler(int sig)
{
//strsiganl 功能是把信號的編號轉為信號說明的字符串
printf(“Rcv a signal:%s”,strsignal(sig));
}
int main()
{
signal(SIGUSR1,handler);
while(1)
;
}
(這段程序其實是有問題的,後面會說到)這段程序本來是一段死循環,但是對他發送SIGUSR1信號,程序會從while中“中斷”轉去執行handler中的代碼。在shell中使用kill命令發送信號SIGUSR1 於是程序就答應出了一段這樣的信息:Rcv a signal:User defined signal 1。signal()的用法幾乎就是這麼簡單。但是由於可移植的原因,參與項目開發時,應該使用下面的這個函數。
sigaction()函數的參數中有兩個結構體,其man手冊原型如下:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
據我所知sa_handler和sa_sigaction其實是在一個union中,他們都是指向信號處理函數的指針。
sa_mask 是要屏蔽的信號,sa_flags 有多種選項。(關於這兩點後文再細說)。從sigaction()原型中可以發現參數中有兩個struct sigaction參數,其中act是要安裝的信號處理,而oldact是用來帶回原來的處理方式方便我們處理完信號後的恢復。如果不需要拿回之前的信號處理方式可以把第三個參數置為NULL,反之如果只想得到之前的處理方式而不像安裝新的信號處理,可以把第二個參數置為NULL,這點用signal()是辦不到的。用sigaction()改寫上面的例子是這樣的:
1 void handler(int sig)
2 {
3 printf(“Rcv a signal:%s”,strsignal(sig));
4 }
5
6 int main()
7 {
8 struct sigaction act;
9 sigemptyset(&act.sa_mask);
10 act.sa_handler = handler;
11 act.sa_flags = 0;
12 sigaction(SIGUSR1,&act,NULL);
13 while(1)
14 ;
15 } 上一頁12下一頁共2頁
2、信號阻塞、信號的未決
sigset_t 是一種將信號類型以為位掩碼形式存在的數據類型(下文都稱之為信號集),他是多種信號的集合(可以保證容納所有的信號)。操作系統的PCB為每個進程都維護了一個這樣的數據類型,並將其內所有的信號阻塞,使他們不可以實時到達進程。當信號屏蔽解除時他們才被傳遞到進程。在這之間的狀態通常被稱為未決(pending)。而在信號阻塞期間多次到來的信號,在信號屏蔽解除時只會被報告一次。
對sigset_t 處理有一系列函數,其中POSIX標准有5個
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
這樣的函數基本上看參數就能知道怎麼用,不在贅述。
glibc中還實現了3個擴展的函數:
int sigisemptyset(sigset_t *set);
int sigorset(sigset_t *dest, sigset_t *left, sigset_t *right);
int sigandset(sigset_t *dest, sigset_t *left, sigset_t *right);
sigprocmask()函數可以檢測和更改信號屏蔽集。
每個進程都有一個用來描述哪些信號遞送到進程時將被阻塞的信號集,該信號集中的所有信號在遞送到進程後都將被阻塞。
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
how
說明
SIG_BLOCK
將set中的信號與原有的取並集,並更新進程的屏蔽字
SIG_UNBLOCK
解除原有的信號集中包含set中的信號,(set補集的交集)
SIG_SETMASK
將進程的屏蔽字設置為set
sigpending函數可以看到信號屏蔽期間那些信號來到過(不計次數的)。
以上就是Linux的信號機制的解析了,當然Linux信號機制是一個相對復雜的系統,本文能夠給大家的是一個初步的了解。
上一頁12 下一頁共2頁