linux訊號的阻塞和未決
阿新 • • 發佈:2019-02-02
執行訊號的處理動作稱為訊號遞達(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:遮蔽狀態字使用者可以讀寫,未決狀態字使用者只能讀;這是訊號設計機制。
API函式:
訊號集操作函式,對狀態字進行操作(遮蔽狀態字和未決狀態字):
還有一個函式可以讀取更改遮蔽狀態字的API函式#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,表示位於在集合中
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
引數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訊號;
/*************************************************************************
> File Name: block_pending.cpp
> Author:
> Mail:
> Created Time: 2015年12月17日 星期四 17時13分45秒
************************************************************************/
#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);
}