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     检查一个信号集中是否有这个信号

  • 信号集增减操作

#include <signal.h>

    int sigemptyset(sigset_t *set);//将set集合置空

  int sigaddset(sigset_t *set,int signo);//将signo信号加入到set集合
  int sigdelset(sigset_t *set,int signo);//从set集合中移除signo信号


   int sigfillset(sigset_t *set); //将所有信号加入set集合

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

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

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

返回值:

         若成功,返回0

         若出错,返回-1

  •  设定对信号集处理方式

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

参数:

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

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

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

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

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

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

返回值:

         若成功,返回0

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

  • 等待信号

int sigsuspend(const sigset_t *sigmask);

//该函数通过将进程的屏蔽字替换为由参数sigmask给出的信号集,然后挂起进程的执行。注意操作的先后顺序,是先替换再挂起程序的执行。程序将在信号处理函数执行完毕后继续执行。

/*
sigsuspend的整个原子操作过程为:
(1) 设置新的mask阻塞当前进程;
(2) 收到信号,恢复原先mask;
(3) 调用该进程设置的信号处理函数;
(4) 待信号处理函数返回后,sigsuspend返回。
*/

参数说明

   sigmask 希望屏蔽的信号

返回值

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

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

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

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

  • 检查和更改阻塞的信号

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
       /* Prototype for the underlying system call */
//可以根据参数指定的方法修改进程的信号屏蔽字。
//新的信号屏蔽字由参数set(非空)指定,而原先的信号屏蔽字将保存在oset(非空)中。
//如果set为空,则how没有意义,但此时调用该函数,如果oset不为空,则把当前信号屏蔽字保存到oset中。

/* 底层系统调用的原型 */
int rt_sigprocmask(int how, const kernel_sigset_t *set,kernel_sigset_t *oldset, size_t sigsetsize);
       /* Prototype for the legacy system call (deprecated) */


int sigpending(sigset_t *set);
//获取信号集,查询被搁置的信号

 参数:

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

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

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

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

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

返回值:

        若成功,返回0

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

泡沫o0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值