執行信號的處理動作稱為信號遞達(Delivery),信號從產生到遞達之間的狀態,稱為信號未決(Pending)。
進程可以選擇阻塞(Block)某個信號。被阻塞的信號產生時將保持在未決狀態,直到進程解除對此信號的阻塞,才執行遞達的動作。注意,阻塞和忽略是不同,只要信號被阻塞就不會遞達,而忽略是在遞達之后可選的一種處理動作。
1:PCB進程控制塊中函數有信號屏蔽狀態字(block)信號未決狀態字(pending)還有是否忽略標志(或是信號處理函數);block狀態字、pending狀態字 64bit;
2:信號屏蔽狀態字(block),1代表阻塞、0代表不阻塞;信號未決狀態字(pending)的1代表未決,0代表信號可以抵達了;它們都是每一個bit代表一個信號,比如,bit0代表信號SIGHUP;
3:比如向進程發送SIGINT,內核首先判斷信號屏蔽狀態字是否阻塞,如果該信號被設為為了阻塞的,那么信號未決狀態字(pending)相應位制成1;若該信號阻塞解除,信號未決狀態字(pending)相應位制成0;表示信號此時可以抵達了,也就是可以接收該信號了。
4:屏蔽狀態字用戶可以讀寫,未決狀態字用戶只能讀(?);這是信號設計機制。
信號集操作函數,對狀態字進行操作(屏蔽狀態字和未決狀態字):
#include <signal.h> int sigemptyset(sigset_t *set);//將信號集清空,共64bits int sigfillset(sigset_t *set);//將信號集置1 int sigaddset(sigset_t *set, int signum);//將signum對應的位置為1 int sigdelset(sigset_t *set, int signum);//將signum對應的位置為0 int sigismember(const sigset_t *set, int signum);//判斷signum是否在該信號集合中,如果集合中該位為1,則返回1,表示位於在集合中
還有一個函數可以讀取更改屏蔽狀態字的API函數
參數how有下面三種取值:
SIG_BLOCK: 將參數set指向的信號集中設置的信號添加到現在的屏蔽狀態字中,設置為阻塞;
SIG_UNBLOCK:將參數set指向的信號集中設置的信號添加到現在的屏蔽狀態字中,設置為非阻塞, 也就是解除阻塞;
SIG_SETMASK:將參數set指向的信號集直接覆蓋現在的屏蔽狀態字的值;
如果oset是非空指針,則讀取進程的當前信號屏蔽字通過oset參數傳出。
若成功則為0,若出錯則為-1
還有一個函數可以讀取未決狀態字(pending)信息
#include <signal.h> int sigpending(sigset_t *set);
SIGINT信號設置阻塞,查看未決關鍵字
發送SIGINT信號,查看未決關鍵字
發送SIGQUIT信號解除SIGINT信號阻塞,查看未決關鍵字
剛開始設置SIGINT信號為阻塞信號,當按下Ctrl+c發送中斷信號SIGINT(值為2,所以后來第二位被置1)之前,未決狀態字的所有位都是0,因為此時沒有未抵達的信號;
當發送SIGINT信號后,因為該信號是阻塞的,所以未決狀態字將第二位置為了1,表示該信號在這里阻塞了;當我按下Ctrl+\發送SIGQUIT信號后,又將SIGINT信號設置為了非阻塞的;
此時可以看到未決狀態字的所有位都變為了0;並且也收到了剛才阻塞的SIGINT信號;
#include <iostream> #include <signal.h> #include <cstdlib> #include <unistd.h> using namespace std; void handler(int num) { if(num == SIGINT){ cout << "剛才收到了信號SIGQUIT, 取消了阻塞,收到中斷信號.." << endl; } else if (num == SIGQUIT){ //將SIGINT信號設置為非阻塞的 sigset_t un_bset; sigemptyset(&un_bset); sigaddset(&un_bset, SIGINT); sigprocmask(SIG_UNBLOCK, &un_bset, NULL); } } void print_pending(sigset_t * pset) { int i = 0; cout << "未決狀態字(64位):"; for (i = 1; i <= 64; ++i){ if(sigismember(pset, i)) cout << 1; else cout << 0; if(i % 8 == 0){ cout << " "; } } cout << endl; } int main() { sigset_t bset; sigset_t pset; //設置SIGINT信號 sigemptyset(&bset); sigaddset(&bset, SIGINT); signal(SIGINT, handler); signal(SIGQUIT, handler); //將SIGINT信號設置為阻塞的 sigprocmask(SIG_BLOCK, &bset, NULL); while(1){ //得到未決狀態字 sigpending(&pset); //顯示未決狀態字 print_pending(&pset); sleep(1); } exit(0); }