利用函数alarm和pause模拟sleep

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章