Linux下定時器的設定
1. alarm函式
[1] 引用標頭檔案:#include <unistd.h>; [2] 函式標準式:unsigned int alarm(unsigned int seconds); [3] 功能與作用:alarm()函式的主要功能是設定訊號傳送鬧鐘,即用來設定訊號SIGALRM在經過引數seconds秒數後傳送給目前的程序。如果未設定訊號SIGALARM的處理函式,那麼alarm()預設處理終止程序。 [4] 函式返回值:如果在seconds秒內再次呼叫了alarm函式設定了新的鬧鐘,則後面定時器的設定將覆蓋前面的設定,即之前設定的秒數被新的鬧鐘時間取代;當引數seconds為0時,之前設定的定時器鬧鐘將被取消,並將剩下的時間返回。
2. 測試
測試環境是Centos7。
瞭解了alarm()函式的功能特性和返回值的特性後,我們就可以對其測試。測試方向有兩個:其一,測試常規只單獨存在一個鬧鐘函式alarm()的程式;其二,測試程式中包含多個alarm()鬧鐘函式。因此整理了下面幾個程式,通過比較學習更有助於理解。測試環境是RedHat Linux5.3,GCC編譯除錯。
2.1 alarm()測試1.1
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> void sig_alarm() { exit(0); } int main(int argc, char *argv[]) { signal(SIGALRM, sig_alarm); alarm(10); sleep(15); printf("Hello World!\n"); return 0; }
程式分析:在檔案test1.c中,定義了一個時鐘alarm(10),它的作用是讓訊號SIGALRM在經過10秒後傳送給目前main()所在程序;接著又定義了sleep(15),它的作用是讓執行掛起15秒的時間。所以當main()程式掛起10秒鐘時,signal函式呼叫SIGALRM訊號的處理函式sig_alarm,並且sig_alarm執行exit(0)使得程式直接退出。因此,printf("Hello World!\n")語句是沒有被執行的。
2.2 alarm()測試1.2
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> void sig_alarm() { exit(0); } int main(int argc, char *argv[]) { signal(SIGALRM, sig_alarm); alarm(10); sleep(5); printf("Hello World!\n"); return 0; }
程式分析:與test1.c檔案不同的是,在檔案test2.c中延時函式為sleep(5),即執行掛起5秒的時間。所以當main()程式掛起5秒鐘時,由於還沒到達設定的鬧鐘10秒,那麼main就執行下面的printf("Hello World!\n")語句;緊接著又執行下面的return 0語句,從而直接退出程式。因此,整個test2.c檔案輸出的內容為:Hello World!。
2.3 alarm()測試2
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void handler()
{
printf("hello\n");
}
void main()
{
int i;
signal(SIGALRM, handler);
alarm(5);
for(i = 1; i < 7; i++)
{
printf("sleep %d ...\n", i);
sleep(1);
}
}
程式分析:在檔案test3.c中,定義時鐘alarm(5),而main()函式中主要是一個for迴圈輸出語句。當main函式執行到i=5時,for迴圈先執行printf("sleep %d ...\n", 5)語句輸出"sleep 5 ...",然後執行sleep(1)語句。此時已經到達鬧鐘時間5秒,因此會把訊號SIGALRM傳送給當前main()函式程序;接著呼叫SIGALRM訊號的處理函式handler,從而輸出"hello",然後又返回到sleep(1)這個點;最後for迴圈執行i=6,輸出"sleep 6",最終延時1秒後結束整個程式。
以上三個程式都只包含一個alarm()鬧鐘函式,下面兩個程式包含兩個alarm()。並且為了更為真切的觀察包含alarm()鬧鐘函式的程式的執行過程,程式通過呼叫系統列印輸出當前時間,通過時間差來進一步理解。
2.4 alarm()測試3.1
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
static void sig_alrm(int signo);
int main(void)
{
signal(SIGALRM,sig_alrm);
system("date");
alarm(20);
sleep(5);
printf("%d\n",alarm(15));
pause();
}
static void sig_alrm(int signo){
system("date");
return;
}
程式分析:在test4.c的main()函式中,先設定了一個鬧鐘函式alarm(20),即在20秒時將SIGALRM訊號傳送送給當前程序;然後又定義了一個延時函式sleep(5),接著又定義了一個鬧鐘函式alarm(15),它的作用是清除前面設定的鬧鐘alarm(20)並返回剩餘的時間20-5=15秒。所以,程式先執行system("date")語句輸出當前時間;然後程序休眠5秒後,程式執行輸出語句printf("%d\n",alarm(15)),由於alarm(15)先返回15秒,即列印輸出15;接著程式執行pause()函式,使當前程序處於掛起狀態,直到捕捉到一個訊號;當再過15秒後,SIGALARM訊號的處理函式sig_alrm執行system("date")語句輸出當前時間;最後pause終止程序。因此,整個程式執行的時間為5+15=20秒。
2.5 alarm()測試3.2
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
static void sig_alrm(int signo);
int main(void)
{
signal(SIGALRM,sig_alrm);
system("date");
alarm(20);
sleep(5);
printf("%d\n",alarm(5));
pause();
}
static void sig_alrm(int signo){
system("date");
return;
}
程式分析:與test4.c檔案不同的是,在檔案test5.c中鬧鐘函式為alarm(5)。因此,整個程式執行的時間為5+5=10秒。值得注意的是,alarm(0)
表示清除之前設定的鬧鐘訊號,並返回0。因為,如果這裡把alarm(5)改成alarm(0),那麼整個程式執行的時間為5+0=5秒。
最後:需要注意的是,原作者在文章中進行了精確的時間計算,而程式執行的結果也與作者的計算一致,但即使如此,計算的結果也是不可信的和計算精確的結果也是不可行的。在某些條件下,我們實際花費和等待的時間很有可能比程式設定的時間要長,而且1秒對於現代的作業系統來說,實在是太長了。