unix程序设计实验五 实现mysleep函数

                                                                           实验五 实现mysleep函数

实验描述

函数名字和原型:

                          unsigned int mysleep(unsigned int);

该函数的功能要求与UNIX的sleep函数一样。

 

要求:

1、使用alarm函数实现定时。

2、必须正确处理mysleep函数中的闹钟与调用者可能设置的闹钟之间的关系。例如,如何解决不同的信号处理函数的保存和恢 复?如何处理调用者设置的闹钟比mysleep函数中的闹钟早响的问题?如何处理调用进程屏蔽SIGALRM信号?

3、不允许出现任何竟态条件(时间窗口)。

4、总之,mysleep的实现细节应当对调用者透明,也就是说, 不论在实现mysleep函数时是否使用了alarm函数,对调用者是 否以及如何使用alarm函数均不应有任何影响。

 

主要原理

 

1、以书中10-21 sleep的可靠实现为蓝本,引入与以前设置的闹钟的交互作用

2、使用flag判断是否存在前置闹钟,存在则返回剩余值,不存在则返回零(保存SIGALARM信号处理程序的地址,并在返回前复位它)

 

实验代码:mysleep.c

 

#include "apue.h"

 

 

static void sig_alrm(int signo)

{

 

}

 

unsigned int mysleep(unsigned int nsecs)

{

   

 

    structsigaction newact, oldact;

   sigset_t newmask, oldmask, suspmask, blockedmask;

    intissuspend = 0;/* SIGALRM是否被阻塞 */

    intisblocked = 0;/* 是否存在未决的SIGALRM */

   unsigned int unslept, slept;

   unsigned int oldalarm;

 

   oldalarm = alarm(0);

 

    /* 保存以前的SIGALRM配置,并设置成我们需要的配置 */

   newact.sa_handler = sig_alrm;

   sigemptyset(&newact.sa_mask);

   newact.sa_flags = 0;

   sigaction(SIGALRM, &newact, &oldact);

 

    /* 处理以前的SIGALRM */

    /* 判断SIGALRM是否被阻塞 */

   sigprocmask(SIG_BLOCK, NULL, &oldmask);

    if(sigismember(&oldmask, SIGALRM)) {

        /*SIGALRM被阻塞 */

       issuspend = 1;

    }

 

    /* 判断是否存在未决的SIGALRM */

    if(sigpending(&blockedmask) < 0) {

       err_sys("sigpending error");

    }

    if(sigismember(&blockedmask, SIGALRM)) {

        /*存在未决的SIGALRM */

       suspmask = oldmask;

       isblocked = 1;

       sigdelset(&suspmask, SIGALRM);

        sigsuspend(&suspmask);

       sigprocmask(SIG_SETMASK, &oldmask, NULL);

    }

 

   sigemptyset(&newmask);

   sigaddset(&newmask, SIGALRM);

   sigprocmask(SIG_BLOCK, &newmask, &oldmask);

 

    #ifdefDEBUG

   printf("DEBUG - oldalarm = %u\n", oldalarm);

    #endif

 

    if((oldalarm != 0) && (oldalarm < nsecs) && (issuspend == 0)){

        /*以前剩余的闹钟值比睡眠时间少且没有被阻塞 */

       alarm(oldalarm);

    }

    else {

        /*以前剩余的闹钟值比睡眠时间多或者被阻塞 */

       alarm(nsecs);

    }

 

   suspmask = oldmask;

   sigdelset(&suspmask, SIGALRM);

   sigsuspend(&suspmask);

 

   unslept = alarm(0);

    sigaction(SIGALRM,&oldact, NULL);

 

   sigprocmask(SIG_SETMASK, &oldmask, NULL);

 

    /* 计算实际睡眠时间 */

    if((oldalarm != 0) && (oldalarm < nsecs) && (issuspend == 0)){

        /*以前的闹钟值比睡眠时间少 */

       slept = oldalarm - unslept;

    }

    else {

        /* 以前的闹钟值比睡眠时间多 */

       slept = nsecs - unslept;

    }

 

    if(isblocked == 1) {

       kill(getpid(), SIGALRM);

    }

    if(slept < oldalarm) {

        /*以前的闹钟值比实际睡眠时间多 */

       alarm(oldalarm - slept);

       return nsecs - slept;

    }

    else {

        if(oldalarm != 0) {

           kill(getpid(), SIGALRM);

        }

       return nsecs - slept;

    }

    return0; /* 出错 */

}

 

四.实验结果

源程序名:mysleep.c

可执行程序名:mysleeep

编译方法:gcc  mysleep.c testsleep.c error2e.c –o mysleep  (注:testsleep.c 文件由老师提供,但为了方便附上这一文件)

结束方法:ctrl+c

运行过程:

1)编译

2)运行

 

 

五 实验小结

通过此次实验学习可以得知:

     sigset_t信号集类型,含有各种类型的信号;sigaction结构出现在sigaction函数中,sigaction函数的功能是检查或修改与指定信号相关联的处理动作

intsigaction(int signo,const struct sigaction *restrict act,const struct sigaction*restrict oact);

    若act指针非空,则要修改其动作。若oact指针非空,则系统经由oact指针返回该信号的上一个动作

    alarm(0)的功能是取消前一个设置的闹钟,并且其返回值是上一个alarm的余留值

 _sleep函数过程

   1.设置newact,对应于SIGALRM的动作

  2.设置newmask,这个信号量集用来屏蔽SIGALRM

  3.alarm(nsecs)

  4. sigsuspend(&suspmask);进程挂起,直到捕捉到一个信号量(任意信号量),返回

  5.unslept=alarm(0)

  6.return(unslept)

 mysleep函数过程

  1.oldAlarm=alarm(0);取消以前设置的alarm,并记录下以前alarm的时间

   2.sigpending(&pendingSigset);取出被阻塞的进程

   3.检查是否有SIGALRM信号,如果有,则释放掉,忽略

   4.case1: alarm(0),sleep(5)

       _sleep(nsecs);直接睡5

   5.case2:alarm(5)sleep(10)

        5秒后发出一个SIGALRM信号,sleep被打断

   6.case3:alarm(10),sleep(5)

       先睡5秒,然后在10s的时候发出SIGALRM信号

   7.case4:如果之前有被pending的信号,在sleep之后raise

 附件:testsleep.c

#include	<signal.h>
#include	<stddef.h>
#include	<time.h>
#include	"apue.h"

static char *testpos;
static unsigned int smallsecs = 5;
static unsigned int bigsecs = 10;

static void sig_alrm(int signo)
{
	printf("%s: SIGALRM is caught\n", testpos);
	return;
}

static void sig_usr1(int signo)
{
	printf("%s: SIGUSR1 is caught\n", testpos);
	return;
}

static void loopwait(unsigned int nsecs)
{
	time_t start;

	start = time(NULL);
	while( time(NULL) < (start + nsecs) );
}


void testsleep(unsigned int oldsecs, unsigned int nsecs)
{
	pid_t pid;
	
	testpos = "in testsleep, 1st pass";
	alarm(oldsecs);
	printf("%s: unslept is %u seconds\n", testpos, mysleep(nsecs) );
	loopwait(bigsecs);
	
	testpos = "in testsleep, 2nd pass";
	if( (pid = fork() ) < 0 )
		err_sys("fork error");
	if( pid == 0) {
		loopwait(2);
		kill(getppid(), SIGUSR1);
		exit(0);
	}
	else {
		alarm(oldsecs);
		printf("%s: unslept is %u seconds\n", testpos, mysleep(nsecs) );
		if( wait(NULL) != pid )
			err_sys("wait error");
	}
}

main()
{
	sigset_t	alrmmask, oldmask;

	setvbuf(stdout, NULL, _IONBF, 0);

	signal(SIGUSR1, sig_usr1);
	signal(SIGALRM, sig_alrm);
	sigemptyset(&alrmmask);
	sigaddset(&alrmmask, SIGALRM);

	printf("set alarm to 0 seconds and sleep 5 seconds\n");
	testsleep(0, 5);
	testpos = "out of testsleep";
	printf("************* 1st sleep test finished *************\n\n");

	printf("set alarm to %u seconds and sleep %u seconds\n", smallsecs, bigsecs);
	testsleep(smallsecs, bigsecs);
	testpos = "out of testsleep";
	loopwait(bigsecs);
	printf("************* 2nd sleep test finished *************\n\n");

	printf("set alarm to %u seconds and sleep %u seconds\n", bigsecs, smallsecs);
	testsleep(bigsecs, smallsecs);
	testpos = "out of testsleep";
	loopwait(bigsecs);
	printf("************* 3rd sleep test finished *************\n\n");
	
	printf("Now SIGALRM is blocked\n");
	sigprocmask(SIG_BLOCK, &alrmmask, &oldmask);
	printf("set alarm to %u seconds and sleep %u seconds\n", smallsecs, bigsecs);
	testsleep(smallsecs, bigsecs);
	testpos = "out of testsleep";
	printf("Now SIGALRM is unblocked\n");
	sigprocmask(SIG_SETMASK, &oldmask, NULL);
	loopwait(bigsecs);
	printf("************* 4th sleep test finished *************\n\n");

	printf("Now SIGALRM is blocked\n");
	sigprocmask(SIG_BLOCK, &alrmmask, &oldmask);
	printf("set alarm to %u seconds and sleep %u seconds\n", bigsecs, smallsecs);
	testsleep(bigsecs, smallsecs);
	testpos = "out of testsleep";
	printf("Now SIGALRM is unblocked\n");
	sigprocmask(SIG_SETMASK, &oldmask, NULL);
	loopwait(bigsecs);
	printf("************* 5th sleep test finished *************\n\n");

	printf("Now SIGALRM is blocked and a SIGALRM is pending\n");
	sigprocmask(SIG_BLOCK, &alrmmask, &oldmask);
	kill(getpid(), SIGALRM);
	printf("set alarm to 0 seconds and sleep 5 seconds\n");
	testsleep(0, 5);
	testpos = "out of testsleep";
	printf("Now SIGALRM is unblocked\n");
	sigprocmask(SIG_SETMASK, &oldmask, NULL);
	printf("************* 6th sleep test finished *************\n\n");
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值