天天看點

Linux定時器的使用

使用定時器的目的無非是為了周期性的執行某一任務,或者是到了一個指定時間去執行某一個任務。要達到這一目的,一般有兩個常見的比較有效的方法。一個是用linux内部的三個定時器,另一個是用sleep, usleep函數讓程序睡眠一段時間,使用alarm定時發出一個信号,還有那就是用gettimeofday, difftime等自己來計算時間間隔,然後時間到了就執行某一任務,但是這種方法效率低,是以不常用。

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.

測試程式:

 cat timer.<b>c</b>

#include &lt;stdio.h&gt;

#include &lt;unistd.h&gt;

#include &lt;sys/time.h&gt;

#include &lt;signal.h&gt;

void func()

{

        printf("2 s reached.\n");

10 

}

11 

12 

int main()

13 

14 

        signal(SIGALRM,func);

15 

        alarm(<b>2</b>);

16 

        while(<b>1</b>);

17 

        return <b>0</b>;

18 

19 

Linux為每個任務安排了3個内部定時器:

ITIMER_REAL:實時定時器,不管程序在何種模式下運作(甚至在程序被挂起時),它總在計數。定時到達,向程序發送SIGALRM信号。

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

ITIMER_PROF:程序在使用者模式(即程式執行時)和核心模式(即程序排程用時)均計數。定時到達産生SIGPROF信号。ITIMER_PROF記錄的時間比ITIMER_VIRTUAL多了程序排程所花的時間。

定時器在初始化是,被賦予一個初始值,随時間遞減,遞減至0後發出信号,同時恢複初始值。在任務中,我們可以一種或者全部三種定時器,但同一時刻同一類型的定時器隻能使用一個。

用到的函數有:

#include &lt;sys/time.h&gt;

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秒,再重新計數。

為了幫助你了解這個問題,我們來看一個例子:

/*

*******************************************************************************************************

** Function name: main()

** Descriptions : Demo for timer.

** Input        : NONE

** Output       : NONE

** Created by   : Chenxibing

** Created Date : <b>2005</b>-<b>12</b>-<b>29</b>

**-----------------------------------------------------------------------------------------------------

** Modified by  :

** Modified Date:

*/

int limit = <b>10</b>;

20 

/* signal process */

21 

void timeout_info(int signo)

22 

23 

    if(limit == <b>0</b>)

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   = <b>0</b>;

38 

    sigemptyset(&amp;act.sa_mask);

39 

    sigaction(SIGPROF, &amp;act, NULL);

40 

41 

42 

/* init */

43 

void init_time(void)

44 

45 

    struct itimerval val;

46 

47 

    val.it_value.tv_sec = <b>1</b>;

48 

    val.it_value.tv_usec = <b>0</b>;

49 

    val.it_interval = val.it_value;

50 

    setitimer(ITIMER_PROF, &amp;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(<b>1</b>);

61 

   return <b>0</b>;

62 

63 

對于ITIMER_VIRTUAL和ITIMER_PROF的使用方法類似,當你在setitimer裡面設定的定時器為ITIMER_VIRTUAL的時候,你把sigaction裡面的SIGALRM改為SIGVTALARM, 同理,ITIMER_PROF對應SIGPROF。

不過,你可能會注意到,當你用ITIMER_VIRTUAL和ITIMER_PROF的時候,你拿一個秒表,你會發現程式輸出字元串的時間間隔會不止2秒,甚至5-6秒才會輸出一個,至于為什麼,自己好好琢磨一下^_^

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

#include &lt;signal.h&gt;

#include &lt;unistd.h&gt;

#include &lt;string.h&gt;

#include &lt;stdio.h&gt;

static char msg[] = "I received a msg.\n";

int len;

void show_msg(int signo)

write(STDERR_FILENO, msg, len);

int main()

struct sigaction act;

union sigval tsval;

act.sa_handler = show_msg;

act.sa_flags = 0;

sigemptyset(&amp;act.sa_mask);

sigaction(50, &amp;act, NULL);

len = strlen(msg);

while ( 1 )

sleep(2); /*睡眠2秒*/

/*向主程序發送信号,實際上是自己給自己發信号*/

sigqueue(getpid(), 50, tsval);

return 0;

看到了吧,這個要比上面的簡單多了,而且你用秒表測一下,時間很準,指定2秒到了就給你輸出一個字元串。是以,如果你隻做一般的定時,到了時間去執行一個任務,這種方法是最簡單的。

下面我們來看看,通過自己計算時間差的方法來定時:

#include &lt;time.h&gt;

static time_t lasttime;

time(&amp;lasttime);

time_t nowtime;

/*擷取目前時間*/

time(&amp;nowtime);

/*和上一次的時間做比較,如果大于等于2秒,則立刻發送信号*/

if (nowtime - lasttime &gt;= 2)

lasttime = nowtime;

這個和上面不同之處在于,是自己手工計算時間差的,如果你想更精确的計算時間差,你可以把 time 函數換成gettimeofday,這個可以精确到微妙。

上面介紹的幾種定時方法各有千秋,在計時效率上、方法上和時間的精确度上也各有不同,采用哪種方法,就看你程式的需要。

本文轉自feisky部落格園部落格,原文連結:http://www.cnblogs.com/feisky/archive/2010/03/20/1690561.html,如需轉載請自行聯系原作者

繼續閱讀