使用定時(shí)器的目的無非是為了周期性的執(zhí)行某一任務(wù),或者是到了一個(gè)指定時(shí)間去執(zhí)行某一個(gè)任務(wù)。要達(dá)到這一目的,一般有兩個(gè)常見的比較有效的方法。一個(gè)是用linux內(nèi)部的三個(gè)定時(shí)器,另一個(gè)是用sleep, usleep函數(shù)讓進(jìn)程睡眠一段時(shí)間,使用alarm定時(shí)發(fā)出一個(gè)信號,還有那就是用gettimeofday, difftime等自己來計(jì)算時(shí)間間隔,然后時(shí)間到了就執(zhí)行某一任務(wù),但是這種方法效率低,所以不常用。
alarm
alarm用在不需要經(jīng)確定時(shí)的時(shí)候,返回之前剩余的秒數(shù)。
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.
測試程序:
1 | cat timer.c |
2 | #include <stdio.h> |
3 | #include <unistd.h> |
4 | #include <sys/time.h> |
5 | #include <signal.h> |
6 | |
7 | void func() |
8 | { |
9 | 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內(nèi)置的3個(gè)定時(shí)器
Linux為每個(gè)任務(wù)安排了3個(gè)內(nèi)部定時(shí)器:
ITIMER_REAL:實(shí)時(shí)定時(shí)器,不管進(jìn)程在何種模式下運(yùn)行(甚至在進(jìn)程被掛起時(shí)),它總在計(jì)數(shù)。定時(shí)到達(dá),向進(jìn)程發(fā)送SIGALRM信號。
ITIMER_VIRTUAL:這個(gè)不是實(shí)時(shí)定時(shí)器,當(dāng)進(jìn)程在用戶模式(即程序執(zhí)行時(shí))計(jì)算進(jìn)程執(zhí)行的時(shí)間。定時(shí)到達(dá)后向該進(jìn)程發(fā)送SIGVTALRM信號。
ITIMER_PROF:進(jìn)程在用戶模式(即程序執(zhí)行時(shí))和核心模式(即進(jìn)程調(diào)度用時(shí))均計(jì)數(shù)。定時(shí)到達(dá)產(chǎn)生SIGPROF信號。ITIMER_PROF記錄的時(shí)間比ITIMER_VIRTUAL多了進(jìn)程調(diào)度所花的時(shí)間。
定時(shí)器在初始化是,被賦予一個(gè)初始值,隨時(shí)間遞減,遞減至0后發(fā)出信號,同時(shí)恢復(fù)初始值。在任務(wù)中,我們可以一種或者全部三種定時(shí)器,但同一時(shí)刻同一類型的定時(shí)器只能使用一個(gè)。
用到的函數(shù)有:
#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; /*時(shí)間間隔*/
struct timeval it_value; /*當(dāng)前時(shí)間計(jì)數(shù)*/
};
it_interval用來指定每隔多長時(shí)間執(zhí)行任務(wù), it_value用來保存當(dāng)前時(shí)間離執(zhí)行任務(wù)還有多長時(shí)間。比如說, 你指定it_interval為2秒(微秒為0),開始的時(shí)候我們把it_value的時(shí)間也設(shè)定為2秒(微秒為0),當(dāng)過了一秒, it_value就減少一個(gè)為1, 再過1秒,則it_value又減少1,變?yōu)?,這個(gè)時(shí)候發(fā)出信號(告訴用戶時(shí)間到了,可以執(zhí)行任務(wù)了),并且系統(tǒng)自動把it_value的時(shí)間重置為it_interval的值,即2秒,再重新計(jì)數(shù)。
為了幫助你理解這個(gè)問題,我們來看一個(gè)例子:
1 | #include <stdio.h> |
2 | #include <signal.h> |
3 | #include <sys/time.h> |
4 | |
5 | /* |
6 | ******************************************************************************************************* |
7 | ** Function name: main() |
8 | ** Descriptions : Demo for timer. |
9 | ** 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的使用方法類似,當(dāng)你在setitimer里面設(shè)置的定時(shí)器為ITIMER_VIRTUAL的時(shí)候,你把sigaction里面的SIGALRM改為SIGVTALARM, 同理,ITIMER_PROF對應(yīng)SIGPROF。
不過,你可能會注意到,當(dāng)你用ITIMER_VIRTUAL和ITIMER_PROF的時(shí)候,你拿一個(gè)秒表,你會發(fā)現(xiàn)程序輸出字符串的時(shí)間間隔會不止2秒,甚至5-6秒才會輸出一個(gè),至于為什么,自己好好琢磨一下^_^
sleep
下面我們來看看用sleep以及usleep怎么實(shí)現(xiàn)定時(shí)執(zhí)行任務(wù)。
- #include <signal.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdio.h>
- 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(&act.sa_mask);
- sigaction(50, &act, NULL);
- len = strlen(msg);
- while ( 1 )
- {
- sleep(2); /*睡眠2秒*/
- /*向主進(jìn)程發(fā)送信號,實(shí)際上是自己給自己發(fā)信號*/
- sigqueue(getpid(), 50, tsval);
- }
- return 0;
- }
看到了吧,這個(gè)要比上面的簡單多了,而且你用秒表測一下,時(shí)間很準(zhǔn),指定2秒到了就給你輸出一個(gè)字符串。所以,如果你只做一般的定時(shí),到了時(shí)間去執(zhí)行一個(gè)任務(wù),這種方法是最簡單的。
時(shí)間差
下面我們來看看,通過自己計(jì)算時(shí)間差的方法來定時(shí):
- #include <signal.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdio.h>
- #include <time.h>
- static char msg[] = "I received a msg.\n";
- int len;
- static time_t lasttime;
- 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(&act.sa_mask);
- sigaction(50, &act, NULL);
- len = strlen(msg);
- time(&lasttime);
- while ( 1 )
- {
- time_t nowtime;
- /*獲取當(dāng)前時(shí)間*/
- time(&nowtime);
- /*和上一次的時(shí)間做比較,如果大于等于2秒,則立刻發(fā)送信號*/
- if (nowtime - lasttime >= 2)
- {
- /*向主進(jìn)程發(fā)送信號,實(shí)際上是自己給自己發(fā)信號*/
- sigqueue(getpid(), 50, tsval);
- lasttime = nowtime;
- }
- }
- return 0;
- }
這個(gè)和上面不同之處在于,是自己手工計(jì)算時(shí)間差的,如果你想更精確的計(jì)算時(shí)間差,你可以把 time 函數(shù)換成gettimeofday,這個(gè)可以精確到微妙。
上面介紹的幾種定時(shí)方法各有千秋,在計(jì)時(shí)效率上、方法上和時(shí)間的精確度上也各有不同,采用哪種方法,就看你程序的需要。
posted on 2012-01-31 09:47
老馬驛站 閱讀(9071)
評論(0) 編輯 收藏 引用 所屬分類:
c++ 、
linux