APUE 第三版 程序 10-8,10-9 (sleep2 函数的缺陷)

如有错误,欢迎批评指正,本人也是才学APUE的菜鸟

/* sleep2 Code*/

#include <setjmp.h>
#include <signal.h>
#include <unistd.h>

static jmp_buf env_alrm;

static void sig_alrm(int signo) {
	longjmp(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);
}
  • 由于直接调用 setjmp 的返回值会 0。所以调用 sleep2 时会直接进入 if 条件。
  • 现假设 alarm(seconds) 与 pause() 函数,在繁忙的系统中,在程序未执行 pause 之前,定时器就超时了,捕捉到 SIGALRM信号,调用 sig_alrm(),然后 longjmp 会跳到 setjmp 的位置,此时 setjmp 的返回值为 1,就不会执行 if 条件中的语句。所以 sleep2 完全可以避免 sleep1 中的 alarm 先超时,然后调用 pause 使进程 (在未捕捉其他信号前) 永远挂起的情况。
     

书中说明了 sleep2 的缺陷:如果 SIGALRM 中断了某个其他处理程序,则调用 longjmp 会提早终止该信号的处理程序

Code 10-9:sleep2 的缺陷,在一个捕捉信号的程序中调用 sleep2

#include "apue.h"
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>

unsigned int sleep2(unsigned int);
static void sig_int(int);

int main(void) {
	unsigned int unslept;
	if(signal(SIGINT, sig_int) == SIG_ERR)
		err_sys("signal(SIGINT) error");
	unslept = sleep2(5);
	printf("sleep2 returned: %u\n", unslept);
	exit(0);
}

static void sig_int(int signo) {
	int i,j;
	volatile int k;

	printf("\nsig_int starting\n");
	for(i = 0;i < 300000;++ i)
		for(j = 0;j < 4000;++ j)
			k += i * j;
	printf("sig_int finished\n");
}

在终端上,运行结果是这样的:

hjm@hjm-Inspiron:~/InterviewPreparation/apue/Examples/10-9$ ./10-9
^C
sig_int starting
sleep2 returned: 0

  从输出中也可以看出,确实 sig_int 并未执行完成,而且 sleep2 也确实休眠了有 5s 的时间。

至于为什么会这样,这肯定是用栈帧来分析的。见下图:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值