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;
}