1信号産生原因
2.程序處理信号行為
manpage裡信号3中處理方式:
sig_ign
sig_dfl
預設term動作
a signal handling function
程序處理信号
a預設處理動作
term
中斷
core
core(調試的時候産生)
gcc –g file.c
ulimit –c 1024
gdb a.out core
ign
忽略
stop
停止
cont
繼續
b忽略
c捕捉(使用者自定義處理函數)
3信号集處理函數
sigset_t為信号集,可sizeof(sigset_t)檢視
将信号集裡面的每位都置0
int sigemptyset(sigset_t *set)
将所有信号集都置1
int sigfillset(sigset_t *set)
添加一個信号,也就是将block阻塞信号集裡面的某一位置成1
int sigaddset(sigset_t *set, int signo)
将信号集中某一位取消置1
int sigdelset(sigset_t *set, int signo)
測試某個信号集中的信号是否為1
int sigismember(const sigset_t *set, intsigno)
4 pcb的信号集
信号在核心中的表示示意圖
如果在程序解除對某信号的阻塞之前這種信号産生過多次,将如何處理?posix.1允
許系統遞送該信号一次或多次。linux是這樣實作的:正常信号在遞達之前産生多次隻
計一次,而實時信号在遞達之前産生多次可以依次放在一個隊列裡。本章不讨論實時信
号。從上圖來看,每個信号隻有一個bit的未決标志,非0即1,不記錄該信号産生了多少
次,阻塞标志也是這樣表示的。是以,未決和阻塞标志可以用相同的資料類型sigset_t
來存儲,sigset_t稱為信号集,這個類型可以表示每個信号的“有效”或“無效”狀态,
在阻塞信号集中“有效”和“無效”的含義是該信号是否被阻塞,而在未決信号集中“有
效”和“無效”的含義是該信号是否處于未決狀态。
阻塞信号集也叫做目前程序的信号屏蔽字(signal mask),這裡的“屏蔽”應該了解
為阻塞而不是忽略。
5sigprocmask
調用函數sigprocmask可以讀取或更改程序的信号屏蔽字。
依賴的頭檔案:
#include <signal.h>
函數聲明:
*set是傳入的信号,*oset表示原來的信号集是什麼,相當于是*set的一個備份
intsigprocmask(int how, const sigset_t *set, sigset_t *oset);
傳回值:若成功則為0,若出錯則為-1
如果oset是非空指針,則讀取程序的目前信号屏蔽字通過oset參數傳出。如果set是非空指針,則更改程序的信号屏蔽字,參數how訓示如何更改。如果oset和set都是非空指針,則先将原來的信号屏蔽字備份到oset裡,然後根據set和how參數更改信号屏蔽字。假設目前的信号屏蔽字為mask,下表說明了how參數的可選值。
how參數的含義
sig_block set包含了我們希望添加到目前信号屏蔽字的信号,相當于mask=mask|set
sig_unblock set包含了我們希望從目前信号屏蔽字中解除阻塞的信号,相當于mask=mask&~set
sig_setmask
設定目前信号屏蔽字為set所指向的值,相當于mask=set
6sigpending(未決列印信号)
#include<signal.h>
int sigpending(sigset_t *set)
sigpending讀取目前程序的未決信号集,通過set參數傳出。調用成功則傳回0,出錯則
傳回-1。
6案例說明:
運作結果:
程式運作時,每秒鐘把各信号的未決狀态列印一遍,由于我們阻塞了sigint信号,按ctrl-c将會使sigint信号處于未決狀态,按ctrl-\仍然可以終止程式,因為sigquit信号沒有阻塞。
這時按ctrl+\結束。
7信号捕捉設定
8.sigaction
int sigaction(int signum, const structsigaction *act,
struct sigaction *oldact);
struct sigaction
定義:
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 :
新添加的捕捉函數,可以傳參,和sa_handler互斥,兩者通過sa_flags選擇采用哪種捕捉函數
sa_mask :
在執行捕捉函數時,設定阻塞其它信号,sa_mask|
程序阻塞信号集,退出捕捉函數後,還原回原有的阻塞信号集
sa_flags : sa_siginfo
或者0
sa_restorer:保留,已過時。
案例說明:
#include<stdio.h>
#include<unistd.h>
void do_sig(int num)
{
int n = 5;
printf("i am do_sig\n");
printf("num = %d\n",num);
while(n--)
{
printf("num = %d\n",num);
sleep(1);
}
}
int main(void)
struct sigaction act;
act.sa_handler = do_sig;
//act.sa_handler = sig_dfl;
//act.sa_handler = sig_ign;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask,sigquit);
act.sa_flags = 0;
sigaction(sigint,&act,null);
while(1)
printf("**********\n");
sleep(1);
return 0;
9 c标準庫信号處理函數
typedef void (*sighandler_t)(int)
sighandler_t signal(int signum,sighandler_t handler)
int system(const char *command)
system的本質是:集合fork,exec,wait一體
10
可重入函數
a:不含全局變量和靜态變量是可重入函數的一個要素
b:可重入函數man
7 signal
c:在信号捕捉函數裡應可重入函數
例如:strtok就是一個不可重入函數,因為strtok内部維護了一個内部靜态指針,儲存上一次切割到的位置,如果信号的捕捉函數中也去調用strtok函數,則會造成切割字元串混亂,應用strtok_r版本,r表示可重入。
11時序競态
int pause(void)
使調用程序挂起,直到有信号遞達,如果遞達信号是忽略,則繼續挂起
int sigsuspend(const sigset_t *mask)
以通過指定mask來臨時解除對某個信号的屏蔽,然後挂起等待,當sigsuspend傳回時,程序的信号屏蔽字恢複為原來的值
#include <unistd.h>
#include <stdio.h>
void sig_alrm(int signo)
/* nothing to do */
unsigned int mysleep(unsigned int nsecs)
struct sigaction newact, oldact;
unsigned int unslept;
newact.sa_handler = sig_alrm;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(sigalrm, &newact, &oldact);
alarm(nsecs);
//在alarm的時候,可能會轉到其它程式,這之後永遠都執行不到下面的這行,因為信号已經執行過了
pause();
unslept = alarm(0);
sigaction(sigalrm, &oldact, null);
return unslept;
while(1){
mysleep(2);
printf("two seconds passed\n");
return 0;
mysleep的改進版
{
/* nothing to do*/
unsigned int mysleep(unsigned int nsecs) {
struct sigaction newact,oldact;
sigset_tnewmask,oldmask,suspmask;
/*set our handler,saveprevious information*/
newact.sa_handler =sig_alrm;
sigemptyset(&newact.sa_mask);
sigaction(sigalrm,&newact,&oldact);
/*block sigalrm and savecurrent signal mask*/
sigemptyset(&newmask);
sigaddset(&newmask,sigalrm);
sigprocmask(sig_block,&newmask,&oldmask);
alarm(nsecs);
suspmask = oldmask;
/*make sure sigalrm isn'tblocked*/
sigdelset(&suspmask,sigalrm);
sigsuspend(&suspmask);/*waitfor any signal to be caught*/
/*some signal has bencaught,sigalrm is now blocked*/
unslept = alarm(0);
sigaction(sigalrm,&oldact,null);/*resetprevious action*/
/*reset signal mask,whichunblocks sigalrm*/
sigprocmask(sig_setmask,&oldmask,null);
return(unslept);
int main(void) {
while(1)
sleep(2);
printf("two secondspassed\n");