当前位置:   article > 正文

Linux系统编程之Linux 信号集编程:信号集的基本概念、用法和实现方式_linux信号集

linux信号集

信号集

表示多个信号的集合

信号在内核中的表示

信号递达(Delivery):实际执行信号处理的动作。 
信号未决(Pending):信号从产生到递达之间的状态。 
信号阻塞(Block)    :被阻塞的信号产生时将保持在未决状态,直到 进程解除对此信号的阻塞,才 执行递达的动作。

注意:

信号阻塞和信号忽略是不同的。只要信号被阻塞就不会递达,除非解除阻塞,而忽略是在递达之后 可选的一种处理动作。 
一个信号处于Pending状态,屏蔽之后,它永远不会被Delivery 。 
一个信号是否立即Delivery ,与Block没有绝对关

3张表的存储: 
pending表:  用4个字节的位图表示,位图的位置表示信号编号,内容表示是否pending。 
block表:      用4个字节的位图表示,位图的位置表示信号编号,内容表示是否block。 
handler表:     是一个句柄函数指针,数组即可表示,下标表示信号编号,内容表示信号处理的动作,为NULL表示没有处理该信号。

分析上图中的信号: 
1〉SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。 
2〉SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。 
3〉 SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。

 

信号集接口函数

sigemptyset     置空一个信号集
sigfillset          填充满一个信号集
sigaddset        将一个信号加入信号集
sigdelset       将一个信号从信号集删除
sigismember     检查一个信号集中是否有这个信号

  • 信号集增减操作

  1. #include <signal.h>
  2. int sigemptyset(sigset_t *set);//将set集合置空
  3.   int sigaddset(sigset_t *set,int signo);//将signo信号加入到set集合
  4.   int sigdelset(sigset_t *set,int signo);//从set集合中移除signo信号
  5. int sigfillset(sigset_t *set); //将所有信号加入set集合

返回值:
         若成功,返回0
         若出错,返回-1

  •  测试信号是否已加入信号集

   int sigismember(const sigset_t *set, int signum); //测试参数signum 代表的信号是否已加入至参数set信号集里

返回值:

         若成功,返回0

         若出错,返回-1

  •  设定对信号集处理方式

  1. int sigdelset(sigset_t *set,int signo);
  2. //设定对信号屏蔽集内的信号的处理方式(阻塞或不阻塞)。

参数:

how:用于指定信号修改的方式,可能选择有三种:

SIG_BLOCK //加入信号到进程屏蔽。

SIG_UNBLOCK //从进程屏蔽里将信号删除。

SIG_SETMASK //将set的值设定为新的进程屏蔽。

set:指向信号集的指针,在此专指新设的信号集,如果仅想读取现在的屏蔽值,可将其置为NULL。

oldset:也是指向信号集的指针,在此存放原来的信号集。

返回值:

         若成功,返回0

         若出错,返回-1,errno被设为EINVAL。

  • 等待信号

  1. int sigsuspend(const sigset_t *sigmask);
  2. //该函数通过将进程的屏蔽字替换为由参数sigmask给出的信号集,然后挂起进程的执行。注意操作的先后顺序,是先替换再挂起程序的执行。程序将在信号处理函数执行完毕后继续执行。
  3. /*
  4. sigsuspend的整个原子操作过程为:
  5. (1) 设置新的mask阻塞当前进程;
  6. (2) 收到信号,恢复原先mask;
  7. (3) 调用该进程设置的信号处理函数;
  8. (4) 待信号处理函数返回后,sigsuspend返回。
  9. */

参数说明

   sigmask 希望屏蔽的信号

返回值

        若接收到信号终止了程序,sigsuspend()就不会返回。

         若出错(接收到的信号没有终止程序),返回-1,并将errno设置为EINTR。   

使用场景:
    sigsuspend() 函数可以更改进程的信号屏蔽字可以阻塞所选择的信号,或解除对它们的阻塞,使用这种技术可以保护不希望由信号中断的代码临界区。
    如果希望对一个信号解除阻塞,然后pause等待以前被阻塞的信号发生,那么必须使用 sigsuspend() 函数, pause() 函数无法达成上述目的.

  • 阻塞信号
  1.     if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
  2.         err_sys("SIG_BLOCK error");
  • 解除阻塞
  1.     if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
  2.         err_sys("SIG_SETMASK error");
  • 等待信号
    pause();   

  • 检查和更改阻塞的信号

  1. int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
  2. /* Prototype for the underlying system call */
  3. //可以根据参数指定的方法修改进程的信号屏蔽字。
  4. //新的信号屏蔽字由参数set(非空)指定,而原先的信号屏蔽字将保存在oset(非空)中。
  5. //如果set为空,则how没有意义,但此时调用该函数,如果oset不为空,则把当前信号屏蔽字保存到oset中。
  6. /* 底层系统调用的原型 */
  7. int rt_sigprocmask(int how, const kernel_sigset_t *set,kernel_sigset_t *oldset, size_t sigsetsize);
  8. /* Prototype for the legacy system call (deprecated) */
  9. int sigpending(sigset_t *set);
  10. //获取信号集,查询被搁置的信号

 参数:

how:不同取值及操作如下所示:

注:调用这个函数才能改变进程的屏蔽字,之前的函数都是为改变一个变量的值而已,并不会真正影响进程的屏蔽字。

SIG_BLOCK :    附加set到阻塞表,原来的保存在到oldset

SIG_UNBLOCK:从阻塞表中删除set中的信号,原来的保存到oldset

SIG_SETMASK:清空阻塞表并设置为set,原来的保存到oldset

返回值:

        若成功,返回0

        若出错(how取值无效返回-1),返回-1,并设置errno为EINVAL。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/864820
推荐阅读
相关标签
  

闽ICP备14008679号