Unix 环境编程10-15 sigjmp longjmp 和 sigsetjmp siglongjmp的比较
文章目录
实验一:信号函数handler 中再次触发同一个信号
实验二 使用longjmp 跳回到main函数中
实验三 使用siglongjmp 跳回到main函数中
UNIX 环境高级编程10-15 介绍siglongjmp和sigsetlongjmp 函数,这里通过3个例子加深理解。
实验一:信号函数handler 中再次触发同一个信号
首先看一般情况下,如果在一个信号执行函数中再此触发同样的信号会是则怎样的情况
void handler(int a){sigset_t sigpend;sigset_t sigmask;sleep(5);sigpending(&sigpend);sigprocmask(0,NULL,&sigmask);if(sigismember(&sigpend,SIGQUIT)){printf("SIGQUIT is pending\n");}else{printf("SIGQUIT is not pending\n");}if(sigismember(&sigmask,SIGQUIT)){printf("SIGQUIT is in sigmask\n");}else{printf("SIGQUIT is not in sigmask\n");}}int main(){int sleep_left;sigset_t sigmask;if(signal(SIGQUIT,handler)==SIG_ERR){printf("signal error\n");exit(1);}sleep_left = sleep(5);sigprocmask(0,NULL,&sigmask);if(sigismember(&sigmask,SIGQUIT)){printf("main : SIGQUIT is in sigmask\n");}else{printf("main : SIGQUIT is not in sigmask\n");}printf("sleep_left = %d\n",sleep_left);exit(0);}
运行结果如下:
$ ./test^\^\SIGQUIT is pendingSIGQUIT is in sigmaskSIGQUIT is not pendingSIGQUIT is in sigmaskmain : SIGQUIT is not in sigmasksleep_left = 3
结果分析:
首先在main中遇到sleep时,触发第一次SIGQUIT信号,当遇到handler中的sleep函数时触发第二次SIGQUIT信号。
第一次进入handler函数时,SIGQUIT就被加入了屏蔽字中,因此SIGQUIT 会在sigmask中,而此时发出来第二次的SIGQUIT信号,因此SIGQUIT信号会被阻塞则会处于pending状态。
第一次handler执行完之后,SIGQUIT信号会从屏蔽字中去除,因此则会处理第二次的SIGQUIT信号,第二次进入handler函数中,此时SIGQUIT依旧会被加入到屏蔽字中,但是由于没有第三个SIGQUIT信号,SIGQUIT不会处于pending状态。
而回到main函数中时,屏蔽字则会恢复,因此SIGQUIT不会在屏蔽字中。
实验二 使用longjmp 跳回到main函数中
static jmp_buf jmpbuf;void handler(int a){sigset_t sigpend;sigset_t sigmask;sleep(5);sigpending(&sigpend);sigprocmask(0,NULL,&sigmask);if(sigismember(&sigpend,SIGQUIT)){printf("SIGQUIT is pending\n");}else{printf("SIGQUIT is not pending\n");}if(sigismember(&sigmask,SIGQUIT)){printf("SIGQUIT is in sigmask\n");}else{printf("SIGQUIT is not in sigmask\n");}longjmp(jmpbuf,1);}int main(){sigset_t sigmask;sigset_t sigpend;if(signal(SIGQUIT,handler)==SIG_ERR){printf("signal error\n");exit(1);}while(setjmp(jmpbuf)==0);sigprocmask(0,NULL,&sigmask);if(sigismember(&sigmask,SIGQUIT)){printf("main : SIGQUIT is in sigmask\n");}else{printf("main : SIGQUIT is not in sigmask\n");}sigpending(&sigpend);if(sigismember(&sigpend,SIGQUIT)){printf("main : SIGQUIT is pending\n");}else{printf("main : SIGQUIT is not pending\n");}exit(0);}
实验结果如下:
$ ./test^\^\SIGQUIT is pendingSIGQUIT is in sigmaskmain : SIGQUIT is in sigmaskmain : SIGQUIT is pending
结果分析:
首先在main中遇到sleep时,触发第一次SIGQUIT信号,当遇到handler中的sleep函数时触发第二次SIGQUIT信号。
第一次进入handler函数时,SIGQUIT就被加入了屏蔽字中,因此SIGQUIT 会在sigmask中,而此时发出来第二次的SIGQUIT信号
因此SIGQUIT信号会被阻塞则会处于pending状态。
第一次handler执行完之后,则会跳转到setjmp函数的位置,此时SIGQUIT仍然屏蔽字中,因此第二次的SIGQUIT信号就不会进入handler函数中,因此在main函数中会输出SIGQUIT在屏蔽字中,SIGQUIT处在pending状态。
而回到main函数中时,屏蔽字则会恢复,因此SIGQUIT不会再屏蔽字中。
实验三 使用siglongjmp 跳回到main函数中
static jmp_buf jmpbuf;void handler(int a){sigset_t sigpend;sigset_t sigmask;sleep(5);sigpending(&sigpend);sigprocmask(0,NULL,&sigmask);if(sigismember(&sigpend,SIGQUIT)){printf("SIGQUIT is pending\n");}else{printf("SIGQUIT is not pending\n");}if(sigismember(&sigmask,SIGQUIT)){printf("SIGQUIT is in sigmask\n");}else{printf("SIGQUIT is not in sigmask\n");}siglongjmp(jmpbuf,1);}int main(){sigset_t sigmask;sigset_t sigpend;if(signal(SIGQUIT,handler)==SIG_ERR){printf("signal error\n");exit(1);}while(sigsetjmp(jmpbuf,1)==0);sigprocmask(0,NULL,&sigmask);if(sigismember(&sigmask,SIGQUIT)){printf("main : SIGQUIT is in sigmask\n");}else{printf("main : SIGQUIT is not in sigmask\n");}sigpending(&sigpend);if(sigismember(&sigpend,SIGQUIT)){printf("main : SIGQUIT is pending\n");}else{printf("main : SIGQUIT is not pending\n");}exit(0);}
实验结果如下:
$ ./test^\^\SIGQUIT is pendingSIGQUIT is in sigmaskSIGQUIT is not pendingSIGQUIT is in sigmaskmain : SIGQUIT is not in sigmaskmain : SIGQUIT is not pending
结果分析:
首先在main中遇到sleep时,触发第一次SIGQUIT信号,当遇到handler中的sleep函数时触发第二次SIGQUIT信号。
第一次进入handler函数时,SIGQUIT就被加入了屏蔽字中,因此SIGQUIT 会在sigmask中,而此时发出来第二次的SIGQUIT信号
因此SIGQUIT信号会被阻塞则会处于pending状态。
第一次handler执行完之后,则会跳转到sigsetjmp函数的位置,此时屏蔽字已经被恢复中,因此第二次的SIGQUIT信号就会进入handler函数中,此时由于没有第三个SIGQUIT信号,所以输出SIGQUIT在屏蔽字中,但不在pending中。随后再次使用siglongjmp跳入main函数中。
回到main函数中,屏蔽字被恢复,因此在main函数中会输出SIGQUIT不在在屏蔽字中,SIGQUIT不处在pending状态。
这里需要注意的时sigsetjmp函数可以设置跳转时是否恢复屏蔽字,上面的例子中设置sigsetjmp(jmpbuf,1)代表会恢复。
而设置sigsetjmp(jmpbuf,0)则不会恢复。
$ ./test^\^\SIGQUIT is pendingSIGQUIT is in sigmaskmain : SIGQUIT is in sigmaskmain : SIGQUIT is pending
最后通过这三个例子做一个总结:
1、信号处理程序正常结束,会自动加触发信号加入屏蔽字,信号处理函数结束,会恢复原来的信号屏蔽字。
2、longjmp跳出信号处理程序,不会恢复原来的信号屏蔽字。
3、siglongjmp的第二个参数非零,恢复信号屏蔽字,为0则不恢复。
