Linux定时器的使用(三种方法)
使用定時(shí)器的目的無(wú)非是為了周期性的執(zhí)行某一任務(wù),或者是到了一個(gè)指定時(shí)間去執(zhí)行某一個(gè)任務(wù)。要達(dá)到這一目的,一般有兩個(gè)常見(jiàn)的比較有效的方法。一個(gè)是用linux內(nèi)部的三個(gè)定時(shí)器,另一個(gè)是用sleep, usleep函數(shù)讓進(jìn)程睡眠一段時(shí)間,使用alarm定時(shí)發(fā)出一個(gè)信號(hào),還有那就是用gettimeofday, difftime等自己來(lái)計(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 aSIGALRMsignal 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.
測(cè)試程序:
| 1 | cattimer.c |
| 2 | #include<stdio.h> |
| 3 | #include<unistd.h> |
| 4 | #include<sys/time.h> |
| 5 | #include<signal.h> |
| 6 | |
| 7 | voidfunc() |
| 8 | { |
| 9 | printf("2sreached. "); |
| 10 | } |
| 11 | |
| 12 | intmain() |
| 13 | { |
| 14 | signal(SIGALRM,func); |
| 15 | alarm(2); |
| 16 | while(1); |
| 17 | return0; |
| 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信號(hào)。
ITIMER_VIRTUAL:這個(gè)不是實(shí)時(shí)定時(shí)器,當(dāng)進(jìn)程在用戶模式(即程序執(zhí)行時(shí))計(jì)算進(jìn)程執(zhí)行的時(shí)間。定時(shí)到達(dá)后向該進(jìn)程發(fā)送SIGVTALRM信號(hào)。
ITIMER_PROF:進(jìn)程在用戶模式(即程序執(zhí)行時(shí))和核心模式(即進(jìn)程調(diào)度用時(shí))均計(jì)數(shù)。定時(shí)到達(dá)產(chǎn)生SIGPROF信號(hào)。ITIMER_PROF記錄的時(shí)間比ITIMER_VIRTUAL多了進(jìn)程調(diào)度所花的時(shí)間。
定時(shí)器在初始化是,被賦予一個(gè)初始值,隨時(shí)間遞減,遞減至0后發(fā)出信號(hào),同時(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用來(lái)指定每隔多長(zhǎng)時(shí)間執(zhí)行任務(wù), it_value用來(lái)保存當(dāng)前時(shí)間離執(zhí)行任務(wù)還有多長(zhǎng)時(shí)間。比如說(shuō), 你指定it_interval為2秒(微秒為0),開(kāi)始的時(shí)候我們把it_value的時(shí)間也設(shè)定為2秒(微秒為0),當(dāng)過(guò)了一秒, it_value就減少一個(gè)為1, 再過(guò)1秒,則it_value又減少1,變?yōu)?,這個(gè)時(shí)候發(fā)出信號(hào)(告訴用戶時(shí)間到了,可以執(zhí)行任務(wù)了),并且系統(tǒng)自動(dòng)把it_value的時(shí)間重置為it_interval的值,即2秒,再重新計(jì)數(shù)。
為了幫助你理解這個(gè)問(wèn)題,我們來(lái)看一個(gè)例子:
| 1 | #include<stdio.h> |
| 2 | #include<signal.h> |
| 3 | #include<sys/time.h> |
| 4 | |
| 5 | /* |
| 6 | ******************************************************************************************************* |
| 7 | **Functionname:main() |
| 8 | **Descriptions:Demofortimer. |
| 9 | **Input:NONE |
| 10 | **Output:NONE |
| 11 | **Createdby:Chenxibing |
| 12 | **CreatedDate:2005-12-29 |
| 13 | **----------------------------------------------------------------------------------------------------- |
| 14 | **Modifiedby: |
| 15 | **ModifiedDate: |
| 16 | **----------------------------------------------------------------------------------------------------- |
| 17 | ******************************************************************************************************* |
| 18 | */ |
| 19 | intlimit=10; |
| 20 | /*signalprocess*/ |
| 21 | voidtimeout_info(intsigno) |
| 22 | { |
| 23 | if(limit==0) |
| 24 | { |
| 25 | printf("Sorry,timelimitreached. "); |
| 26 | return; |
| 27 | } |
| 28 | printf("only%dsencondsleft. ",limit--); |
| 29 | } |
| 30 | |
| 31 | /*initsigaction*/ |
| 32 | voidinit_sigaction(void) |
| 33 | { |
| 34 | structsigactionact; |
| 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 | voidinit_time(void) |
| 44 | { |
| 45 | structitimervalval; |
| 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 | intmain(void) |
| 55 | { |
| 56 | init_sigaction(); |
| 57 | init_time(); |
| 58 | printf("Youhaveonly10secondsforthinking. "); |
| 59 | |
| 60 | while(1); |
| 61 | return0; |
| 62 | } |
| 63 |
對(duì)于ITIMER_VIRTUAL和ITIMER_PROF的使用方法類似,當(dāng)你在setitimer里面設(shè)置的定時(shí)器為ITIMER_VIRTUAL的時(shí)候,你把sigaction里面的SIGALRM改為SIGVTALARM, 同理,ITIMER_PROF對(duì)應(yīng)SIGPROF。
不過(guò),你可能會(huì)注意到,當(dāng)你用ITIMER_VIRTUAL和ITIMER_PROF的時(shí)候,你拿一個(gè)秒表,你會(huì)發(fā)現(xiàn)程序輸出字符串的時(shí)間間隔會(huì)不止2秒,甚至5-6秒才會(huì)輸出一個(gè),至于為什么,自己好好琢磨一下^_^
sleep
下面我們來(lái)看看用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.
";
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ā)送信號(hào),實(shí)際上是自己給自己發(fā)信號(hào)*/
sigqueue(getpid(), 50, tsval);
}
return 0;
}
看到了吧,這個(gè)要比上面的簡(jiǎn)單多了,而且你用秒表測(cè)一下,時(shí)間很準(zhǔn),指定2秒到了就給你輸出一個(gè)字符串。所以,如果你只做一般的定時(shí),到了時(shí)間去執(zhí)行一個(gè)任務(wù),這種方法是最簡(jiǎn)單的。
時(shí)間差
下面我們來(lái)看看,通過(guò)自己計(jì)算時(shí)間差的方法來(lái)定時(shí):
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
static char msg[] = "I received a msg.
";
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ā)送信號(hào)*/
if (nowtime - lasttime >= 2)
{
/*向主進(jìn)程發(fā)送信號(hào),實(shí)際上是自己給自己發(fā)信號(hào)*/
sigqueue(getpid(), 50, tsval);
lasttime = nowtime;
}
}
return 0;
}
這個(gè)和上面不同之處在于,是自己手工計(jì)算時(shí)間差的,如果你想更精確的計(jì)算時(shí)間差,你可以把 time 函數(shù)換成gettimeofday,這個(gè)可以精確到微妙。
上面介紹的幾種定時(shí)方法各有千秋,在計(jì)時(shí)效率上、方法上和時(shí)間的精確度上也各有不同,采用哪種方法,就看你程序的需要。
https://blog.csdn.net/skc361/article/details/20544933
總結(jié)
以上是生活随笔為你收集整理的Linux定时器的使用(三种方法)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 使用EclEmma 插件 解析jacoc
- 下一篇: 委托(Delegate)简介