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