panse()要等信号处理完成后才能返回,遇到信号,linux会中断当前任务跳转去执行信号处理,处理完成再跳转回中断的地方继续。这段代码是《unix环境高级编程》中摘的,运行时按下ctrl+c,程序收到(ctrl+c产生的中断)信号,跑去执行sig_int函数,如果执行sig_int函数中途有遇到alarm产生的闹钟信号,又中断当前sig_int的任务,跑去sig_alrm函数,
若sig_alrm中没有跳转jmp就等sig_alrm执行完成就跑回sig_int中断处继续,sig_int完了,pause()返回,main继续。
若是有跳转jmp,那就跟着jmp走以前的就不管了,不跳回去了。
#include
#include
#include
#include
#include
static jmp_buf env_alrm;
//若启用jmp跳转,与函数sig_int中的循环
//则不会有 printf("\nline 39:sig_int finished\n");因为按下ctl+c中断时,
//程序中断当前任务(睡眠),跑去调用sig_int函数处理,
//sig_int函数处理【完成后】,25行的【pause()才能返回】,
//但是sig_int处理时间长于5秒,alarm时间到了,程序从sig_int中断跑去
//执行sig_alrm函数,当启用longjmp时程序就不会跳转回以前中断的地方继续了,
//导致sig_int函数中断后没有继续,运行结果:
//[root@localhost code]# ./alarm.o
//^C ctrl+c 中断
//line 31:sig_int starting:pid=2585
//line 11:sig_alrm pid=2585
//line 25 exit sleep2
//line 50:main-sleep2 returned:unslept=0;pid=2585
static void sig_alrm(int signo)
{
printf("line 11:sig_alrm pid=%d\n",getpid());
//sleep(3);
// longjmp(env_alrm,1);
}
unsigned int sleep2(unsigned int nsecs)
{
if(signal(SIGALRM,sig_alrm)==SIG_ERR)
return(nsecs);
// if(setjmp(env_alrm)==0)
// {
alarm(nsecs);
pause();
// }
printf("line 25 exit sleep2\n");
return(alarm(0));
}
static void sig_int(int signo)
{
volatile int k;
int i,j;
printf("\nline 31:sig_int starting:pid=%d\n",getpid());
//若注释掉这段循环,运行结果
//[root@localhost code]# ./alarmAndPause.o
//line 31:sig_int starting:pid=2452
//^C 运行一秒时ctrl+c 中断
//line 39:sig_int finished
//line 25 exit sleep2
//line 50:main-sleep2 returned:unslept=4;pid=2452
//因为闹钟时间还没到
//所以没有打印sig_alrm中的 printf("line 11:sig_alrm pid=%d\n",getpid());
for(i=0;i<500000;i++)//要使循环运行时间大于五秒
{
for( j=0 ; j<10000;j++ )
{
k+=i*j;
//printf("line 37:loop i=%d;j=%d;k=%d\n",i,j,k);
}
}
printf("\nline 39:sig_int finished\n");
}
int main(int argc, char *argv[])
{
unsigned int unslept;
if(signal(SIGINT,sig_int)==SIG_ERR)
{
printf("signal(sigint) err\n");
exit(-1);
}
unslept=sleep2(5);
printf("line 50:main-sleep2 returned:unslept=%u;pid=%d\n",unslept,getpid());
exit(0);
}