利用函数alarm和pause模拟sleep

来源:互联网 发布:用c语言求最大公约数 编辑:程序博客网 时间:2024/06/16 12:36

1. 简单介绍sig alarm(unsigned int alam)

当在调用alarm()前已经设置了一个闹钟,那么我们可以调用alarm(0)来取消此闹钟,并返回剩余时间

2. int pause(void)

pause函数使调用进程挂起, 直到捕捉到一个信号(出错返回)所以我们需要对信号进行自定义捕捉

3. 普通sleep

void myhandler(int sig)//{    //printf("get a sig: %d\n",sig);}unsigned mysleep(size_t  s_time){    struct sigaction act, oact;    act.sa_handler = myhandler;//    sigemptyset(&act.sa_mask); //清空    act.sa_flags = 0;    sigaction(SIGALRM,&act,&oact);//信号自定义捕捉,并保存老的屏蔽字    alarm(s_time);    pause();//挂起等待alarm信号抵达//bug!!    int ret = alarm(0);//返回给外层,判断时间是否成功    sigaction(SIGALRM,&oact,NULL);    return ret;}

2.改进版sleep

可以看到普通sleep是有bug的,pause不仅可有alarm信号唤醒,也可是其他信号,再者当pause执行后,进程被切出去,直到alarm信号已经抵达后,才被切回来,导致pause一直等待信号。
方法:
1. 屏蔽SIGALRM信号;
2. alarm(nsecs);
3. pause();
4. 解除对SIGALRM信号的屏蔽;
但我么需要把“解除信号屏蔽”和“挂起等待信号”这两步能合并成⼀一个原⼦子操作。而这正是sigsuspend
函数的功 能。sigsuspend包含了pause的挂起等待功能,同时解决了竞态条件的问题,在对
时序要求严格的场合下都应该调⽤用sigsuspend⽽而不是pause。

void myhandler(int sig){}int mysleep(size_t w_time){    struct sigaction act, oact;    sigset_t newsig,oldsig,susig;//创建block    act.sa_handler = myhandler;    sigemptyset(&act.sa_mask); //清空    act.sa_flags = 0;    sigemptyset(&newsig);//清空    sigaddset(&newsig,SIGALRM);屏蔽字添加SIGALRM    sigprocmask(SIG_BLOCK,&newsig,&oldsig);//设置屏蔽字    sigaction(SIGALRM,&act,&oact);//定义捕捉信号    alarm(w_time);//定时    susig = oldsig;    sigdelset(&susig,SIGALRM);//    sigsuspend(&susig);解除对SIGALRM同时挂起等待    int ret = alarm(0);    sigprocmask(SIG_BLOCK,&oldsig,NULL);//返回原来的信号屏蔽字    return ret;}