目录
一.sigaction () ;
struct sigaction结构体的成员:
sigaction()和signal()函数的区别:
二.sigaction函数的使用
sigaction函数使用案例1: 对该进程发送指定的信号
案例2:对该进程发送多个同类型的信号时:
案例2与案例3的不同之处在于:
三.总结:
一.sigaction () ;
该函数功能是为信号指定相关的处理程序,但是它在执行信号处理程序时,会把当前信号加入到进程的信号屏蔽字中,从而防止在进行信号处理期间信号丢失。
该函数的第二三参数类型是一个结构体,act表示指定新的信号处理方式,oldact参数输出先前信号的处理方式(如果不为NULL的话)。
说白了sigaction函数的作用和之前学过的signal函数的作用一样,全都是针对特定的信号进行信号捕捉,从而进行自定义式的信号处理。
struct sigaction结构体的成员:
sa_handler: 类型是函数指针,该成员和signal的参数handler相同,代表捕获普通信号并对齐做处理的函数;
sa_sigaction:该成员与sa_handler也一样是函数指针,但它用于对实时信号的捕获;
sa_mask: 用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置;
sa_flags: 用来设置信号处理的其他相关操作,下列的数值可用:1.SA RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值;
2.SIG DFLSA RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用;
3.SA NODEFER:当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号。
sa_flags默认情况下赋值0即可。
sigaction()和signal()函数的区别:
1.signal只能捕获信号,对信号进行处理。但是不能获取信号的其它信息;
2.sigaction可以使用sigaction结构体的sa_handler函数对信号进行处理(此处等同于signal函数),也可以使用sa_sigactior函数查看信号的各种详细信息;
3.并且sigaction函数还可以通过sa_mask、sa_flags对信号处理时进行很多其他操作。
二.sigaction函数的使用
sigaction函数使用案例1: 对该进程发送指定的信号
代码解析:通过struct sigaction结构体创建对象,利用对象的成员变量为其赋值,对OS发送给该进程的SIGINT2号信号进行信号捕捉。
运行结果:
专门设置的捕获2号信号,所以我用ctrl+c键向该进程发送2号信号,被sigaction函数捕获,因为sigaction函数的第二参数为新的处理方式newact代替了旧的处理方式oldact,即对象newact的处理方式为自定义方式,调用该对象的成员handler方法。
每当我发送2号信号,总能被sigaction函数捕获;而当我发送其他信号(例如3号信号)给该进程时,进程收到对3号信号做递达处理,采用默认的递达动作,立即终止进程。
案例2:对该进程发送多个同类型的信号时:
代码解析: 当2号信号被进程接收并递达时,因为sigcation函数采用的是自定义方式处理,所以调用handler方法,里面有Count函数,Count函数的作用就是一个倒数10秒的定时器,当2号信号被捕获处理时,10秒后可以完成对信号的处理。相比情况1,代码上只增加了这处。
运行结果:
例:从上面结果右图可知,我向该进程连续发送5次2号信号后,当发送的第一个2号信号被sigcation函数捕获后,它会告知系统让系统将2号信号加入到进程的信号屏蔽字(阻塞位图sa_mask成员),也就是将该进程阻塞位图的第2比特位置1,让第二次及后面向进程发送的2号信号无法递达该进程。当进程递达(自定义)处理完第一个送来的2号信号后,系统又会解除对2号信号的屏蔽,让第二次发送到进程的2号信号能够被进程收到,递达时被捕获,此时,系统又会对阻塞位图的第2比特位进行屏蔽,直到第二次送来的2号信号被进程递达完毕,才会解除对2号信号的屏蔽。
注意:在上图案例中向进程发送来的5次二号信号中,只有前两次被发送来的2号信号被进程递达处理,剩下的3次都被进程丢弃。原因就是sigcation函数只能对多次发送的同类型信号的前两次进行处理,剩下的均被丢弃。
当右侧窗口在发送五次2号信号一段时间之后,又发送了两次2号信号,情况仍同上面一样,先捕获第一个,屏蔽后面的一个,处理完第一个后,开放第二个2号信号,该2号又被捕获,被进程的handler回调函数处理。
案例3:对该进程发送不同类型的多个信号时,sigaction函数对其他信号的屏蔽:
代码解析:这段代码上,新增了容器vector,我将想要屏蔽的信号3,4,5存入容器中,当第一个信号:2号被发送且被进程接收处理时,OS会将阻塞位图中的2号和3,4,5号信号都屏蔽掉。
运行解析:对进程连续发送3次2号信号以及两次3号信号,第一个2号信号被进程递达捕获,此时系统将阻塞信号位图中第2、3、4、5位置的比特位置1,那么后面的2、3、4、5号信号都无法被进程递达。等到第一个2号信号递达完毕,系统解除了对2、3、4、5号的阻塞,第2个2号信号被进程捕获处理,同理,当2号信号被处理完毕后,系统又取消了对2、3、4、5号信号的屏蔽,因为同类型的多次2号信号中只有前两次能够被处理,第3个2号信号被丢弃,然后紧接着被发送来的第一个3号信号被进程处理,因为sigaction函数没有设置3号信号的捕获,所以进程做默认递达处理,退出进程。
案例2与案例3的不同之处在于:
案例2与案例3在运行过程中,都向该进程发送了3号信号,但处理的方式并不同。案例2的2号信号仍在被进行自定义捕获处理(10秒内)过程内,OS就向进程发送3号信号,由于没有针对3号信号的捕获,进程立即对3号信号做默认递达处理,在2号信号还没有被递达完毕时,进程就立即自我终止;
而案例3的2号信号在被进行捕获处理的过程中(10秒内),向进程发送了3号信号,因为sigaddset函数添加过3号信号的原因,在2号信号被捕获处理的一瞬间,系统也就屏蔽阻塞了2号3号的信号,导致进程无法立即对3号信号做默认递达处理,需要等到第2个二号信号被递达处理完毕,进程才能递达处理3号信号,完成默认自我终止。
三.总结:
所以针对信号发送给进程后,进程对这些信号的各种情况我们都大概理解了,总结出来就是:
1.当我们对某个进程连续发送多个同类型的信号时,进程处理信号的原则是: 串行处理(一个一个处理)同类型的信号,不允许递归处理。所以在上面情况中,5次发送同类型的2号信号,只有前两次的能被处理,而且还是第一次的处理完,第二次的2号信号才能接着被处理,这就是串行处理。
2.当进程下递达某一个信号期间,同举型信号无法递达。因为同类型的信号已经被系统加入到了进程的信号屏蔽字一一block。
3.当该信号被递达完毕,系统会解除对同类型信号的屏蔽,进程就会自动进程递达当前的已取消屏蔽的信号。例:当第一个2号信号被进程涕达完毕,系统解除了同举型2号信号的屏蔽,那么第一个2号信号(之前被屏藏、现在肥消屏蔽)会自动被进程递法注:进程只会自动递达这么一个,不会继续自动递达第3次同类型信号,表明了5次中只有前2次能够被处理,剩余的都被丢弃。