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 pending
SIGQUIT is in sigmask
SIGQUIT is not pending
SIGQUIT is in sigmask
main : SIGQUIT is not in sigmask
sleep_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 pending
SIGQUIT is in sigmask
main : SIGQUIT is in sigmask
main : 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 pending
SIGQUIT is in sigmask
SIGQUIT is not pending
SIGQUIT is in sigmask
main : SIGQUIT is not in sigmask
main : 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 pending
SIGQUIT is in sigmask
main : SIGQUIT is in sigmask
main : SIGQUIT is pending
最后通过这三个例子做一个总结:
1、信号处理程序正常结束,会自动加触发信号加入屏蔽字,信号处理函数结束,会恢复原来的信号屏蔽字。
2、longjmp跳出信号处理程序,不会恢复原来的信号屏蔽字。
3、siglongjmp的第二个参数非零,恢复信号屏蔽字,为0则不恢复。