Linux環境程式設計之訊號處理(三、利用alarm()和pause()函式實現sleep()函式)
sleep()是執行掛起一段時間,而alarm()函式是定時器,pause()函式則是掛起程序,當出現訊號打斷時,才會繼續往前執行;
先來分享下alarm()函式,alarm()函式用來設定一個定時器,當時間超時時,會產生SIGALRM訊號,該訊號預設是終止該程序;
#include<unistd.h>
unsigned int alarm(unsigned int seconds);
引數:unsigned int seconds表示經過seconds秒後會產生訊號SIGALRM;
返回值:0或者以前設定的鬧鐘時間的餘留秒數;
1、每個程序只能有一個鬧鐘時鐘;
2、呼叫alarm()時,假如以前呼叫過alarm()函式,並且指定的時間還沒到(即:還沒超時,沒有傳送SIGALRM訊號)。那麼此次呼叫的alarm()函式會替代掉上一次的alarm()函式,並且返回值為上次呼叫alarm()函式中沒有用完的時間;
3、本次呼叫alarm(0)函式會取消上一次未超時的定時器,返回剩餘的時間;
下面也看看pause()函式:
#include<unistd.h>
int pause(void);
pause()會把程序掛起來,直到一個訊號處理程式執行完後,才會繼續執行;
最後看看sleep()函式:
#include<unistd.h>
unsigned int sleep(unsigned int seconds);
該函式使呼叫程序被掛起了,直到seconds後(超時後),或者捕捉到一個訊號並且從訊號處理函式返回後,該程序才能繼續往下執行;返回值和alarm()函式的一樣。
下面是利用alarm()函式和pause()函式來實現下sleep()函式:
#include<stdio.h> #include<signal.h> #include<setjmp.h> #include<unistd.h> static jmp_buf envAlarm; static void myAlarm(int signo)// 自定義的SIGALRM定時器訊號的處理函式 { longjmp(envAlarm, 1);// 區域性跳轉 } unsigned int mySleep(unsigned int sec) { unsigned int minSec, ret, tmp = 0; if (signal(SIGALRM, myAlarm) == SIG_ERR)// 繫結SIGALRM和myAlarm()函式 return sec; minSec = alarm(0);// 得到上一次未超時的定時器所剩的時間,防止沖刷掉上一次的真正的定時器(本函式的是實現sleep()) ret = sec > minSec ? (sec-minSec):0;// 得到返回值 if (setjmp(envAlarm) == 0){ // 區域性跳轉 if (minSec) // 這裡考慮的是如果前面有設定定時器 alarm(minSec < sec ? minSec:sec);// 利用時間短的去做定時器 else // 如果前面沒有設定定時器,則直接利用引數去掛起程序 alarm(sec); sleep(9);// 這裡是測試上一個alarm()函式到pause()之間延遲導致SIGALRM訊號處理完後,pause()還沒有觸犯,則程序一直掛起 pause(); } tmp = alarm(0);// 計算在睡眠時 有可能被其他訊號打斷,而剩下一些未睡眠的時間 if (minSec > sec){// 如果前面登記的定時器比睡眠時間長,則退出後還要把定時器復位為剩下時間的定時器 alarm(minSec-sec);// 定時器還剩多少時間,重新設定定時器 } if (tmp)ret += tmp; // 統計所有剩餘時間 return ret; } int main(int argc, char* argv[]) { unsigned int otherSec; alarm(6); //sleep(4); otherSec = mySleep(3); printf("mySleep resturn:%u\n", otherSec); return 0; }
上面是通過區域性跳轉來實現sleep()函式的,當然還有使用訊號遮蔽字來實現的,後面有時間會實現下。不知道上面的程式碼是否有漏洞,雖然這個程式碼量不多,但是要考慮的問題還是比較多的。如果有朋友發現了漏洞,歡迎指正!!謝謝!!
若有不正確之處,望大家指正,共同學習!謝謝!!!