1、概念
ctrl-c給進程發送一個SIGINT的信號,這個信號的默認處理動作是終止進程,ctrl-c產生的信號只能發給前臺進程
進程收到信號,不是立即處理,而是先記錄起來恰當時候再處理
2、信號列表
使用kill -l顯示系統的所有信號,1-31爲普通信號(31個),34-64爲實時信號(31個)
3、產生信號
(1)通過鍵盤發送信號給前臺,例如ctrl-c產生SIGINT信號,ctrl-\產生SIGQUIT信號,ctrl-z產生SIGTSTP信號
(2)硬件異常
(3)通過指令
alarm函數
#include<stdio.h>
#include<unistd.h>
int main()
{
int count=0;
alarm(1);
for(;2;count++){
printf("count=%d\n",count);
}
return 0;
}
此函數作用爲:1秒鐘不停的數數,1秒鐘到了就被SIGALRM信號終止
4、信號處理(信號遞達)
(1)忽略信號
(2)執行默認處理動作
(3)自定義處理信號的函數(捕捉信號)
5、阻塞信號
實際執行信號的處理動作,稱爲信號遞達;信號從產生到遞達之間的狀態,稱爲信號未決。進程可以選擇阻塞某個信號,被阻塞的信號產生時將保持在未決狀態,直到進程解除對此信號的阻塞,才執行遞達的動作。
阻塞是暫時不處理此信號,而忽略則是處理此信號;信號產生與阻塞無關,遞達與解除阻塞無關
信號在內核中的表示示意圖
POSIX.1允許系統遞送該信號一次或多次,常規信號在遞達之前產生多次只計一次,而實時信號在遞達之前產生多次可以依次放在一個隊列裏。圖中每個信號只有一個bit的未決標誌,非0 即1,不記錄該信號產生了多少次,阻塞信號也這樣表示
未決和阻塞標誌用相同的數據類型sigset_t來存儲,sigset_t稱爲信號集
阻塞信號集也稱爲當前進程的信號屏蔽字
6、信號集操作函數
#include<signal.h>
int sigemptyset(sigset_t *set)//使所有信號對應的bit清零(初始化狀態)
int sigfillset(sigset_t *set)//使所有信號對應的bit置位(初始化)
int sigaddset(sigset_t *set, int signo)//添加某種信號
int sigdelset(sigset_t *set, int signo)//刪除某種信號
int sigismember(const sigset_t *set, int signo)//布爾函數,判斷信號集有效信號中是否包含某種信號,包含返回1,不包含返回0,出錯返回-1
7、sigprocmask
調用函數sigprocmask可以讀取或更改進程的信號屏蔽字
函數原型:
#include<signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset)
返回值:若成功則爲0,若出錯爲-1
若oset是非空指針,則讀取進程的當前信號屏蔽字通過oset參數傳出;若set是非空指針,則更改進程的信號屏蔽字由how指示如何更改;若oset和set都是非空指針,則先將原來的信號屏蔽字備份到oset裏,然後根據set和how參數更改信號屏蔽字
如果調用sigprocmask解除了對當前若干個未決信號的阻塞,則在sigprocmask返回前,至少將其中一個信號遞達。
8、sigpending
#include<signal.h>
int sigpending(sigset_t *set)
sigpending讀取當前進程的未決信號集,通過set參數傳出,調用成功返回0,出錯返回-1
幾個函數的代碼實現:
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void printsigset(sigset_t *set)
{
int i=0;
for(;i<32;i++){
if(sigismember(set, i)){ // 判斷指定信號是否在目標集合中
putchar('1');
}else{
putchar('0');
}
}
puts("\0");
}
int main()
{
sigset_t s,p;
sigemptyset(&s); // 定義信號集對象,並清空初始化
sigaddset(&s,SIGINT); // ctrl-c操作
sigprocmask(SIG_BLOCK,&s,NULL); //設置阻塞信號集,設置SIGINT信號
while(1){
sigpending(&p); //獲取未決信號集
printsigset(&p);
sleep(1);
}
return 0;
}