Linux定時器的使用

使用定時器的目的無非是爲了週期性的執行某一任務,或者是到了一個指定時間去執行某一個任務。要達到這一目的,通常有兩個常見的比較有效的方法。一 個是用linux內部的三個定時器,另外一個是用sleep, usleep函數讓進程睡眠一段時間,使用alarm定時發出一個信號,還有那就是用gettimeofday, difftime等本身來計算時間間隔,而後時間到了就執行某一任務,可是這種方法效率低,因此不經常使用。linux

alarm

alarm用在不須要經肯定時的時候,返回以前剩餘的秒數。函數

NAME
       alarm - set an alarm clock for delivery of a signal
SYNOPSIS
       #include <unistd.h>
       unsigned int alarm(unsigned int seconds);
DESCRIPTION
       alarm  arranges  for a SIGALRM signal to be delivered to the process in
       seconds seconds.
       If seconds is zero, no new alarm is scheduled.
       In any event any previously set alarm is cancelled. 測試

測試程序:spa

 cat timer.c
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
 
void func()
{
        printf("2 s reached.\n");
10  }
11   
12  int main()
13  {
14          signal(SIGALRM,func);
15          alarm(2);
16          while(1);
17          return 0;
18  }
19   

Linux內置的3個定時器

Linux爲每一個任務安排了3個內部定時器: 進程

ITIMER_REAL:實時定時器,無論進程在何種模式下運行(甚至在進程被掛起時),它總在計數。定時到達,向進程發送SIGALRM信號。 ip

ITIMER_VIRTUAL:這個不是實時定時器,當進程在用戶模式(即程序執行時)計算進程執行的時間。定時到達後向該進程發送SIGVTALRM信號。  ci

ITIMER_PROF:進程在用戶模式(即程序執行時)和核心模式(即進程調度用時)均計數。定時到達產生SIGPROF信號。ITIMER_PROF記錄的時間比ITIMER_VIRTUAL多了進程調度所花的時間。 字符串

定時器在初始化是,被賦予一個初始值,隨時間遞減,遞減至0後發出信號,同時恢復初始值。在任務中,咱們能夠一種或者所有三種定時器,但同一時刻同一類型的定時器只能使用一個。 get

 

用到的函數有: string

#include <sys/time.h>
int getitimer(int which, struct itimerval *value);
int setitimer(int which, struct itimerval*newvalue, struct itimerval* oldvalue);
strcut timeval
{
long tv_sec; /*秒*/
long tv_usec; /*微秒*/
};
struct itimerval
{
struct timeval it_interval; /*時間間隔*/
struct timeval it_value;   /*當前時間計數*/
};

it_interval 用來指定每隔多長時間執行任務, it_value用來保存當前時間離執行任務還有多長時間。好比說, 你指定it_interval爲2秒(微秒爲0),開始的時候咱們把it_value的時間也設定爲2秒(微秒爲0),當過了一秒, it_value就減小一個爲1, 再過1秒,則it_value又減小1,變爲0,這個時候發出信號(告訴用戶時間到了,能夠執行任務了),而且系統自動把it_value的時間重置爲 it_interval的值,即2秒,再從新計數。

爲了幫助你理解這個問題,咱們來看一個例子:

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
 
/*
*******************************************************************************************************
** Function name: main()
** Descriptions : Demo for timer.
** Input        : NONE
10  ** Output       : NONE
11  ** Created by   : Chenxibing
12  ** Created Date : 2005-12-29
13  **-----------------------------------------------------------------------------------------------------
14  ** Modified by  :
15  ** Modified Date:
16  **-----------------------------------------------------------------------------------------------------
17  *******************************************************************************************************
18  */
19  int limit = 10;
20  /* signal process */
21  void timeout_info(int signo)
22  {
23      if(limit == 0)
24      {
25          printf("Sorry, time limit reached.\n");
26          return;
27      }
28      printf("only %d senconds left.\n", limit--);
29  }
30   
31  /* init sigaction */
32  void init_sigaction(void)
33  {
34      struct sigaction act;
35   
36      act.sa_handler = timeout_info;
37      act.sa_flags   = 0;
38      sigemptyset(&act.sa_mask);
39      sigaction(SIGPROF, &act, NULL);
40  }
41   
42  /* init */
43  void init_time(void)
44  {
45      struct itimerval val;
46   
47      val.it_value.tv_sec = 1;
48      val.it_value.tv_usec = 0;
49      val.it_interval = val.it_value;
50      setitimer(ITIMER_PROF, &val, NULL);
51  }
52   
53   
54  int main(void)
55  {
56      init_sigaction();
57      init_time();
58      printf("You have only 10 seconds for thinking.\n");
59   
60      while(1);
61     return 0;
62  }
63   

對 於ITIMER_VIRTUAL和ITIMER_PROF的使用方法相似,當你在setitimer裏面設置的定時器爲ITIMER_VIRTUAL的時 候,你把sigaction裏面的SIGALRM改成SIGVTALARM, 同理,ITIMER_PROF對應SIGPROF。

不過,你可能會注意到,當你用ITIMER_VIRTUAL和ITIMER_PROF的時候,你拿一個秒錶,你會發現程序輸出字符串的時間間隔會不止2秒,甚至5-6秒纔會輸出一個,至於爲何,本身好好琢磨一下^_^

sleep

下面咱們來看看用sleep以及usleep怎麼實現定時執行任務。

  1. #include <signal.h>
  2. #include <unistd.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. static char msg[] = "I received a msg.\n";
  6. int len;
  7. void show_msg(int signo)
  8. {
  9. write(STDERR_FILENO, msg, len);
  10. }
  11. int main()
  12. {
  13. struct sigaction act;
  14. union sigval tsval;
  15. act.sa_handler = show_msg;
  16. act.sa_flags = 0;
  17. sigemptyset(&act.sa_mask);
  18. sigaction(50, &act, NULL);
  19. len = strlen(msg);
  20. while ( 1 )
  21. {
  22. sleep(2); /*睡眠2秒*/
  23. /*向主進程發送信號,其實是本身給本身發信號*/
  24. sigqueue(getpid(), 50, tsval);
  25. }
  26. return 0;
  27. }

看到了吧,這個要比上面的簡單多了,並且你用秒錶測一下,時間很準,指定2秒到了就給你輸出一個字符串。因此,若是你只作通常的定時,到了時間去執行一個任務,這種方法是最簡單的。

時間差

下面咱們來看看,經過本身計算時間差的方法來定時:

 

  1. #include <signal.h>
  2. #include <unistd.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <time.h>
  6. static char msg[] = "I received a msg.\n";
  7. int len;
  8. static time_t lasttime;
  9. void show_msg(int signo)
  10. {
  11. write(STDERR_FILENO, msg, len);
  12. }
  13. int main()
  14. {
  15. struct sigaction act;
  16. union sigval tsval;
  17. act.sa_handler = show_msg;
  18. act.sa_flags = 0;
  19. sigemptyset(&act.sa_mask);
  20. sigaction(50, &act, NULL);
  21. len = strlen(msg);
  22. time(&lasttime);
  23. while ( 1 )
  24. {
  25. time_t nowtime;
  26. /*獲取當前時間*/
  27. time(&nowtime);
  28. /*和上一次的時間作比較,若是大於等於2秒,則馬上發送信號*/
  29. if (nowtime - lasttime >= 2)
  30. {
  31. /*向主進程發送信號,其實是本身給本身發信號*/
  32. sigqueue(getpid(), 50, tsval);
  33. lasttime = nowtime;
  34. }
  35. }
  36. return 0;
  37. }

這個和上面不一樣之處在於,是本身手工計算時間差的,若是你想更精確的計算時間差,你能夠把 time 函數換成gettimeofday,這個能夠精確到微妙。

上面介紹的幾種定時方法各有千秋,在計時效率上、方法上和時間的精確度上也各有不一樣,採用哪一種方法,就看你程序的須要。

相關文章
相關標籤/搜索