阻塞信号及信号屏蔽pending

1.信号在内核中的三种表示

(1)信号递达:实际执行信号的处理动作;

(2)信号未决(pending):信号从产生到递达的状态,是一种记录状态;

(3)阻塞信号(block):被阻塞的信号不会递达,它在产生时处于未决状态,直到进程解除对这个信号的阻塞,才会执行递达,但不会立即递达;

阻塞与忽略的不同:忽略是在信号递达后的处理动作,而被阻塞的信号是不会递达的;

2.信号在内核中的表示示意图:

(1)每个PCB都包含三张表:block,pending,handler,block表和pending表有可以有相同的数据结构,是一张位图,占四个字节,pending表的0、1表示是否收到信号,block表的0、1表示是否被阻塞;

(2)每个信号都有阻塞标志位block、未决标志位pending和一个处理动作handler;

(3)信号产生时,内核在PCB中设置未决标志位,当信号递达时才清除该标志位;
阻塞信号及信号屏蔽pending_第1张图片

上述图中:
①1号信号未阻塞也未递达;
②2号信号被阻塞,暂时不会递达;
③3号信号未产生过,一旦产生将被阻塞;

3.信号集

未决标志和阻塞标志可以通过相同的数据类型sigset_t存储,叫做信号集;

阻塞信号集也可以叫做信号屏蔽字;

信号集操作有很多函数,将在下面的信号屏蔽中进行介绍;

4.信号屏蔽
(1)sigprocmask函数: 可以读取或更改进程的信号屏蔽字;

int sigprocmask(int how, const sigset_t *set , sigset_t *oset);
成功时返回0,出错返回-1

①oset非空时,读取进程的当前信号屏蔽字通过pset参数传出;

②set非空时,更改进程的信号屏蔽字;

③两个指针都非空时,将原来的信号屏蔽字输出备份至oset,并根据how和set更改信号屏蔽字;

④how参数:
SIG_BLOCK—–set包含要添加的信号;
SIG_UNBLOCK—-set包含要解除阻塞的信号;
SIG_SETMASK—-设置当前信号屏蔽字为set的值;

(2)pending函数:读取当前进程的未决信号集

int pending(sigset_t *set);
成功时返回0,失败时返回-1

(3)测试信号屏蔽与解除并递达:
最终代码3可以多次发送2号信号并解除,递达
①代码1:

#include
#include
#include

void showpending(sigset_t *pending)
{
    int i=1;
    for(;i<=31;i++)
    {
        if(sigismember(pending,i))//判断指定信号是否在目标集合中
        {
            printf("1");
        }
        else
        {
            printf("0");
        }
    }
    printf("\n");
}

int main()
{
    sigset_t blockset,oblockset,pending;
    sigemptyset(&blockset);//初始化信号集
    sigemptyset(&oblockset);//初始化信号集
    sigaddset(&blockset,2);//在信号集中添加2号信号ctrl-c
    sigprocmask(SIG_SETMASK,&blockset,&oblockset);//设置当前的信号屏蔽字,并备份
    while(1)
    {
        sigpending(&pending);//获取pending表
        showpending(&pending);
        sleep(1);
    }
}

结果如图:

阻塞信号及信号屏蔽pending_第2张图片

程序每秒将31个信号的未决状态打印一遍,按ctrl-c后第二个比特位变为1,因为2号信号被屏蔽,不能递达,所以不被处理。
②代码2:

#include
#include
#include

void handler(int sig)
{
    printf("get a sig:%d\n",sig);
}

void showpending(sigset_t *pending)
{
    int i=1;
    for(;i<=31;i++)
    {
        if(sigismember(pending,i))
        {
            printf("1");
        }
        else
        {
            printf("0");
        }
    }
    printf("\n");
}

int main()
{
    sigset_t blockset,oblockset,pending;
    sigemptyset(&blockset);
    sigemptyset(&oblockset);
    sigaddset(&blockset,2);
    signal(2,handler);//捕捉2号信号
    sigprocmask(SIG_SETMASK,&blockset,&oblockset);
    int count=0;
    while(1)
    {
        sigpending(&pending);
        showpending(&pending);
        sleep(1);
        if(count++==10)//当count加到10时,解除阻塞
        {
           printf("recover proc block set!\n");
           sigprocmask(SIG_SETMASK,&oblockset,NULL);
        }
    }
}

结果如图:

阻塞信号及信号屏蔽pending_第3张图片

③代码3:

#include
#include
#include

void handler(int sig)
{
    printf("get a sig:%d\n",sig);
}

void showpending(sigset_t *pending)
{
    int i=1;
    for(;i<=31;i++)
    {
        if(sigismember(pending,i))
        {
            printf("1");
        }
        else
        {
            printf("0");
        }
    }
    printf("\n");
}

int main()
{
    sigset_t blockset,oblockset,pending;
    sigemptyset(&blockset);
    sigemptyset(&oblockset);
    sigaddset(&blockset,2);
    while(1)//多加了一个循环,让它可以多次屏蔽2号信号,并解除、递达
    {
       signal(2,handler);
       sigprocmask(SIG_SETMASK,&blockset,&oblockset);
       int count=0;
       while(1)
       {
          sigpending(&pending);
          showpending(&pending);
          sleep(1);
          if(count++==10)
          {
             printf("recover proc block set\n");
             sigprocmask(SIG_SETMASK,&oblockset,NULL);
             break;//每次完成解除时,内层循环结束
          }
       }
    }
}

结果如图:

阻塞信号及信号屏蔽pending_第4张图片

你可能感兴趣的:(Linux,信号屏蔽,阻塞信号,pending)