linux信號--阻塞與未決


執行信號的處理動作稱為信號遞達(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函數

 #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信號;
#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);
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM