內核通過讀取未決信號集來判斷信號是否應被處理。信號屏蔽字mask可以影響未決信號集。而我們可以在應用程序中自定義set來改變mask。已達到屏蔽指定信號的目的。綜上:自定義信號集set(也為一個字,64位)通過信號集操作函數來改變信號屏蔽字mask,然后mask進一步來影響未決信號集,從而控制信號是否應該被屏蔽。后面我們只是研究常規信號,即1~31號!
(1)信號集的設置
sigset_t? set;???????? // typedef unsigned long sigset_t; ?聲明一個信號集變量set,信號集類型為sigset_t,為unsigned long(無符號長整型),64位。
int sigemptyset(sigset_t *set);?????? //將set所指信號集清0??????? 成功:0;失敗:-1
int sigfillset(sigset_t *set);??????????? //將set所指信號集置1??????? 成功:0;失敗:-1
int sigaddset(sigset_t *set, int signum); ?????? //將某個信號加入信號集(即將其置1)? 成功:0;失敗:-1
int sigdelset(sigset_t *set, int signum);? ?????? //將某個信號清出信號集(即將其置0)? 成功:0;失敗:-1
int sigismember(const sigset_t *set, int signum); 判斷某個信號是否在信號集中(是否為1)返回值:在集合:1;不在:0;出錯:-1?
sigset_t類型的本質是位圖。但不應該直接使用位操作,而應該使用上述函數,保證跨系統操作有效。
對比認知select 函數。
(2)sigprocmask函數
用來屏蔽信號或解除屏蔽,即用于讀取和修改進程的信號屏蔽字mask。在用戶設置好自己的信號集set后,通過sigprocmask函數,可以利用set來對mask進行修改,以實現屏蔽和解除屏蔽的目的。
注意:屏蔽信號只是將信號處理延后執行(延至解除屏蔽);而忽略表示將信號丟棄處理。
?
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);???
返回值: 成功:0;失敗:-1,設置errno
參數how:1.SIG_BLOCK: 當how設置為此值,set表示需要屏蔽的信號。相當于 mask = mask|set,即將set中為1的信號添加到mask中,mask中原有的信號不變;2.SIG_UNBLOCK: 當how設置為此,set表示需要解除屏蔽的信號。相當于 mask = mask & ~set(先對set位取反,再位與操作),即將set中為1的信號對應的mask中將其置為0(解除屏蔽),其余信號不變;3.SIG_SETMASK:當how設置為此,set表示用于替代mask的新屏蔽集。相當于 mask = set。調用sigprocmask解除了對當前若干個信號的阻塞,則在sigprocmask返回前,至少將其中一個信號遞達。
參數set:傳入參數,是一個位圖,自己設置。
參數oldset:傳出參數,保存舊的信號屏蔽集,即在該函數對mask處理前的mask的值。 如果不關心上一次的屏蔽字mask是什么,第三個參數可以設為NULL。
(3)sigpending函數
作用:讀取當前進程的未決信號集
int sigpending(sigset_t *set);?? set傳出參數。?? 返回值:成功:0;失敗:-1,設置errno
?
//練習:編寫程序。把所有常規信號的未決狀態打印至屏幕。?????
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>void printset(sigset_t *ped) //打印出ped所指信號集的前1~31位(常規信號)
{int i;for(i = 1; i < 32; i++){if( (sigismember(ped, i) == 1) ){putchar('1'); //標準輸出} else if( (sigismember(ped, i) == 0) ) {putchar('0');} else {perror( “sigismember”);exit(1);}}printf("\n");
}int main(void)
{sigset_t set, ped;
#if 0 sigemptyset(&set); //清0sigaddset(&set, SIGINT); //加入2號信號sigaddset(&set, SIGQUIT); //加入3號信號sigaddset(&set, SIGKILL); //加入9號信號,記住其不可以被阻塞、忽略和捕捉sigaddset(&set, SIGSEGV); //加入11號信號
#endifsigfillset(&set); //全部置1,則所有信號全部設置為阻塞sigprocmask(SIG_BLOCK, &set, NULL); //不獲取原屏蔽字while(1){sigpending(&ped); //獲取未決信號集printset(&ped);sleep(1);}return 0;
}
[root@localhost 01_signal_test]# ./sigpending
0000000000000000000000000000000
0000000000000000000000000000000
^Z0000000000000000000100000000000? //Ctrl +Z? 20號信號
^C0100000000000000000100000000000? //Ctrl +C? 2號信號
^\0110000000000000000100000000000?? //Ctrl +\? ?3號信號
0110000000000000000100000000000???
0110000000000000000100000000000
0110000000000000000100000000000
0110000000100000000100000000000? //? [root@localhost ~]# kill -11 5710
?
通過以上可以看出:發送的信號全部被阻塞,在未決信號集中都置為1。最后發送9號信號,殺死該進程。