阻塞信号及相关的函数

1、信号的其他的常见的概念

  • 实际执行信号的处理动作称为信号抵达(Delivery)
  • 信号从产生到抵达之间的状态称为信号未决(Pending)
  • 进程可以选择阻塞(Block)某个信号
  • 被阻塞的信号产生时保持在未决状态,直到进程解除对此信号的阻塞,才执行抵达的动作
  • 注意阻塞和忽略是不同的,只要信号被阻塞就不会抵达,而忽略是在抵达之后可选的一种处理动作。

2、内核中的表示

这里写图片描述
我们可以从中知道:
1)每个信号都有两个标志位分别表示堵塞(block)和未决(pending)还有一个函数指针来表示处理动作。
2)信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号抵达才清除该标志。
3)在上面的这个例子中我们可以看到的是SIGHUP这个信号未阻塞也从未产生过,,当它抵达的时候执行默认处理动作。SIGINT信号产生过,但正在被阻塞,所以并不能抵达,虽然它的处理动作是忽略,但是在没有解除堵塞之前,不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除堵塞。
4)SIGQUIT信号从未产生过,一旦产生将被堵塞,它的处理动作是用户自定义函数sighandler。
5)Linux中,常规信号,在抵达之前产生多次,只计算一次,而实时信号在抵达之前产生多次可以依次的放在队列里。

3、信号集(sigset_t)

从上图看出,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的,因此阻塞和未决可以用相同的数据类型sigset_t来存储,sigset_t被称为信号集。
阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask)这里的屏蔽理解成阻塞而不是“忽略”。

4、信号集操作函数

sigset_t类型对于每种信号用一个bit表示“有效”和“无效”两种状态。使用者只能调用下面的函数来操作信号集变量,而不是直接对它的内部数据做任何解释,比如用printf直接打印sigset_t变量是没有意义的。

  #include  <signal.h>
  //初始化set指向的信号集,使其中所有信号对应的bit位都清零,表示该信号集不包括任何有效信号,成功返回0,出错返回-1
  int sigemptyset(sigset_t *set);
  //初始化set指向的信号集,使其中所有的信号对应的bit位置为1,表示该信号集的有效信号,包括系统支持的所有信号,成功返回0,出错返回-1
  int sigfillset(sigset_t *set);
  //添加某个有效信号,成功返回0,出错返回-1
  int sigaddset(aigset_t *setint signo);
  //删除某个有效信号,成功返回0,失败返回-1
  int sigdeset(sigset_t *set,int signo);
  //判断一个信号集的有效信号中是否包含某个信号,若包含返回1,不包含返回0,若出错返回-1
  int sigismember(const sigset_t *set,int signo);

sigprocmask函数

调用该函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)

这里写图片描述

假设当前的信号屏蔽字为mask,下表说明了how参数的可选值

SIG_BLOCK set包含了我们希望添加到当前信号屏蔽字的信号,相当于mask=mask~set
SIG_UNBLOCK set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask&~set
SIG_SETMASK 设置当前信号屏蔽字为set所指向的值,相当于mask=set

如果调用了sigprocmask函数解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中的一个信号抵达。
sigpending函数
这里写图片描述
读取当前进程的信号未决信号集,通过set参数传出。调用成功返回0,出错返回-1
简单的小应用:

 1 #include <stdio.h>                                                                                                                                                                                                                                                                                                                      
  2 #include <signal.h>
  3 #include <unistd.h>
  4 
  5 void printsigset(sigset_t *set)
  6 {
  7     int i=0;
  8     for(;i<32;i++)
  9         //以此判断第i个信号是否为有效信号
 10     {
 11         if(sigismember(set,i))
 12         {
 13             //如果试有效信号则输出
 14             putchar('1');
 15         }
 16         else
 17             //不是有效信号输出0
 18             putchar('0');
 19     }
 20     puts(" ");
 21 }
 22 
 23 int main()
 24{
 25     //定义两个信号集
 26     sigset_t s,p;
 27     // 将信号集s初始化,即使其中所有信号对应的bit位置为0,表示该信号集不包括任何有效的信号
 28     sigemptyset(&s);
 29     //将SIGINT信号在信号集s中设置为有效信号
 30     sigaddset(&s,SIGINT);
 31     //调用sigprocmask函数,更改信号屏蔽字,将信号集s中的有效信号添加到当前进程的阻塞信号集
 32     //即将SIGINT信号阻塞
 33     sigprocmask(SIG_BLOCK,&s,NULL);
 34     while(1)
 35     {
 36         //调用该函数读取当前进程的未决信号集
 37         sigpending(&p);
 38         //每隔1秒打印当前进程的未决信号集
 39         printsigset(&p);
 40         sleep(1);
 41     }
 42     return 0;
 43 }
 44 

这里写图片描述
程序运行时,每秒钟把各信号的未决状态打印一遍,由于我们阻塞了SIGINT信号,按Ctrl+C将会一直使SIGINT信号处于未决状态,按Ctrl +\仍然可以终止程序,因为SIGQUIT信号没有阻塞。

猜你喜欢

转载自blog.csdn.net/daboluo521/article/details/80134958
今日推荐