目录

一.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次能够被处理,剩余的都被丢弃。

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐