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