先放定义
1. signal函数
#include<singal.h>
void (*signal(int signo, void(*func)(int))(int);
函数原型主体部分是signal(int signo, void (*func)(int)),其中signo就是要设置的信号名参数,而func函数是针对signo信号的处理方式。func可以是常量SIG_IGN、SIG_DFL或者一个函数地址,分别代表:忽视该信号、使用系统默认方式处理该信号、使用指定函数处理该信号。看到此处如果还不理解可以继续往下看或者参考APUE10.3节内容。
2.setjmp和longjmp
#include<setjmp.h>
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);
先说参数,env是一种jump_buf类型的变量,它是某种形式的数组,存放在调用longjmp时能够用来回复栈状态的所有信息,一般是全局变量。val是一个整型变量。
再说用法。setjmp设置一个标记位置,程序通过longjmp可以跨越函数调到这个标记位置处执行。其中setjmp的返回 值就是longjmp的val变量。通过不同val值的longjmp跳跃,setjmp可以返回不同值,从而进行不同的处理。
同样,可以参考apue7.10节内容。
用法
下面结合apue的图10-8程序来说一下我的理解。
1. 图10-8
#include<setnmp.h>
#include<signal.h>
#include<unistd.h>
static jmp_buf env_alrm;
static void sig_alrm(int signo)
{
long jmp(env_alrm, 1);
}
unsigned int sleep2(unsigned int seconds)
{
if(signal(SIGALRM, sig_alrm) == SIG_ERR)
return(seconds);
if(setjmp(env_alrm) == 0)
{
alarm(seconds);
pause();
}
return(alarm(0));
}
2. 程序流程
当sleep2被调用时发生以下情况。
1)首先执行 第一个if内的signal运行,它将SIGALRM(闹钟信号)设置成:当SIGALRM发生时,捕获该信号,并用sig_alrm信号处理程序处理该信号。signal设置失败,则返回SIG_ERR,从而让if语句返回return(seconds)函数。如果设置成功,那么程序执行下一个if。注意:signal设置成功之后,sig_alrm在SIGALRM信号发生时自动调用,signal函数的作用只是设置好要调用的信号处理程序。
2)第二个if内的setjmp函数执行,注意,此时是程序顺序执行到此处,setjmp函数返回值为0。如果是从longjmp返回到此处,那么setjmp返回值为longjmp的参数val。
3)执行alrm(seconds)函数,它设置一个seconds的倒计时。如果超时则内核将发生一个SIGALRM信号。
4)这一步将是不确定的,有两种情况。第一种是顺序执行pause()。它阻塞程序的运行,知道有一个信号发生,在这里就是SIGALRM的发生。有信号发生后,程序顺序执行return(alrm(0))。第二中情况是在程序调用pause()前,SIGALRM已经 发生。这是有可能的一种情况,特别是当系统比较繁忙的时候。CPU可能在执行完alarm之后,就去处理其他程序了,然后又在alarm超时之后回来本程序。此时,pause还没有运行,但SIGALRM已经 发生,那么程序就会调用信号处理程序sig_alrm,它又调用longjmp返回到第二个if的setjmp,setjmp返回val值(此处为1)。第二个if的判断式不成立,程序执行return(alarm(0))。
注:alarm、pause等函数如有不懂请自行百度。