1. 程式人生 > >Linux下定時器的設定

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秒對於現代的作業系統來說,實在是太長了。