setjmp 及 alarm实现带超时限制调用read

setjmp和longjmp函数--非局部跳转语句。

非局部指的是,这不是由普通C语言goto,语句在一个函数内实施的跳转,而是在栈上跳过若干调用帧,返回到当前函数调用路径上的某一个函数中。

#include 
Int setjmp(jmp_buf  env);
   返回值:若直接调用则返回0,若从longjmp调用返回则返回非0值
void longjmp(jmp_buf env,int val);
    在希望返回到的位置调用setjmp,此位置在main函数中,因为直接调用该函数,所以其返回值为0.setjmp参数evn的类型是一个特殊的类型jmp_buf,这一数据类型是某种形式的数组,其中存放在调用longjmp时能用来恢复栈状态的所有信息。因为需要在另一个函数中引用env变量,所以规范的处理方式是将env变量定义为全局变量。

应用:

当检查到一个错误时,则以两个参数调用longjmp函数,第一个就是在调用setjmp时所用的env,第二个参数是具有非0值的val,它将成为从setjmp处返回的值。使用第二个参数的原因是对于一个setjmp可以有多个longjmp。

注: longjmp必须在setjmp调用之后,而且longjmp必须在setjmp的作用域之内。具体来说,在一个函数中使用setjmp来初始化一个全局标号,然后只要该函数未曾返回,那么在其它任何地方都可以通过longjmp调用来跳转到 setjmp的下一条语句执行。实际上setjmp函数将发生调用处的局部环境保存在了一个jmp_buf的结构当中,只要主调函数中对应的内存未曾释放 (函数返回时局部内存就失效了),那么在调用longjmp的时候就可以根据已保存的jmp_buf参数恢复到setjmp的地方执行。


#include 
#include 
#include 
#include  //signal
#include  //alarm
#include  //setjmp and longjmp

#define MAXBUFFLEN 1024

/*
*使用longjmp 及 alarm实现带超时限制调用read
*/

static void sig_alrm(int signo);//声明alarm信号处理函数

static jmp_buf env_alrm;

int main(int argc, char *argv[])
{
	int n;
	char buf[MAXBUFFLEN];

	memset(buf, 0x00, sizeof(buf));

	if(signal(SIGALRM, sig_alrm) == SIG_ERR){
		printf("signal(SIGALRM) Error\n");
		exit(-1);
	}
	//第一次调用setjmp会返回0,当longjmp被调用后,代码会跳转到setjmp处执行,setjmp将会返回longjmp设置的值。
	if(setjmp(env_alrm) != 0){
		printf("read timeout...\n");
		exit(-2);
	}

	alarm(10);
	printf("please intupt some char:");
	fflush(stdout);
	if((n == read(STDIN_FILENO, buf, MAXBUFFLEN)) < 0){
		printf("read error...\n");
		exit(-3);
	}
	alarm(0);
	//buf[MAXBUFFLEN-1] = '\0';
	//printf("%s\n", buf);
	write(STDOUT_FILENO, buf, n);
	
	return 0;
}

static void sig_alrm(int signo){
	longjmp(env_alrm, 1);
}

[huangbin@devsrv3 ~]$ make setjmp
cc     setjmp.c   -o setjmp
[huangbin@devsrv3 ~]$ ./setjmp
please intupt some char:read timeout...
[huangbin@devsrv3 ~]$ ./setjmp
please intupt some char:hello,world!
[huangbin@devsrv3 ~]$



你可能感兴趣的:(C语言)